Automated merge with https://hg.mozilla.org/mozilla-central
authorMike Conley <mconley@mozilla.com>
Thu, 23 May 2013 09:39:09 -0400
changeset 169888 9134b509cb1beb73cce20388b123a1115ac29c17
parent 144232 8eebe35aae634198ce92014e1d4dc8dff5ff228b (current diff)
parent 169887 fad70df06e51da51cb1b1eb14cad67b975b67f99 (diff)
child 169889 0adccd52443ef9c191b447eacfc7e8afe9cb41ec
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)
milestone24.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
Automated merge with https://hg.mozilla.org/mozilla-central
browser/app/profile/firefox.js
browser/base/content/browser-appmenu.inc
browser/base/content/browser.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/components/nsBrowserGlue.js
browser/themes/osx/browser.css
browser/themes/osx/tabbrowser/tab-bottom-hover-active.png
browser/themes/osx/tabbrowser/tab-bottom-normal-active.png
browser/themes/osx/tabbrowser/tab-bottom-selected-active.png
browser/themes/osx/tabbrowser/tab-top-hover-active.png
browser/themes/osx/tabbrowser/tab-top-hover-active@2x.png
browser/themes/osx/tabbrowser/tab-top-normal-active.png
browser/themes/osx/tabbrowser/tab-top-normal-active@2x.png
browser/themes/osx/tabbrowser/tab-top-selected-active.png
browser/themes/osx/tabbrowser/tab-top-selected-active@2x.png
browser/themes/windows/appmenu-dropmarker.png
browser/themes/windows/appmenu-icons.png
layout/style/nsCSSProps.cpp
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/cocoa/nsNativeThemeCocoa.h
widget/cocoa/nsNativeThemeCocoa.mm
--- a/accessible/tests/mochitest/tree/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/tree/test_tabbrowser.xul
@@ -94,30 +94,45 @@
           // NB: The (3) buttons are not visible, unless manually hovered,
           //     probably due to size reduction in this test.
           tabsAccTree.children.splice(0, 0,
             {
               // xul:tab ("about:")
               role: ROLE_PAGETAB,
               children: [
                 {
+                  // :before and :after image
+                  // (selected tab border on left/right)
+                  role: ROLE_GRAPHIC,
+                  children: []
+                },
+                {
+                  role: ROLE_GRAPHIC,
+                  children: []
+                },
+                {
                   // xul:toolbarbutton ("Close Tab")
                   role: ROLE_PUSHBUTTON,
                   children: []
                 }
               ]
             },
             {
               // tab ("about:mozilla")
               role: ROLE_PAGETAB,
               children: [
                 {
                   // xul:toolbarbutton ("Close Tab")
                   role: ROLE_PUSHBUTTON,
                   children: []
+                },
+                {
+                  // :after image (separator)
+                  role: ROLE_GRAPHIC,
+                  children: []
                 }
               ]
             },
             {
               // xul:toolbarbutton ("Open a new tab")
               role: ROLE_PUSHBUTTON,
               children: []
             }
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -408,20 +408,20 @@ 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);
--- a/browser/base/content/browser-addons.js
+++ b/browser/base/content/browser-addons.js
@@ -410,8 +410,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('http://www.mozilla.com/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,102 @@
+# -*- 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;
+    }
+  },
+
+  _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();
+    TabsInTitlebar.allowedBy("customizing-toolbars", false);
+  },
+
+  _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();
+    }
+
+    TabsInTitlebar.allowedBy("customizing-toolbars", true);
+
+    // 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-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.
     document.getElementById("View:FullScreen").setAttribute("checked", enterFS);
 
 #ifdef XP_MACOSX
     // Make sure the menu items are adjusted.
     document.getElementById("enterFullScreenItem").hidden = enterFS;
     document.getElementById("exitFullScreenItem").hidden = !enterFS;
 #endif
 
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -377,16 +377,18 @@ var FullZoom = {
    *                            result, which updates the current zoom level.
    *                            If suppressZoomChange is true, then the next
    *                            call to onContentPrefSet will not update the
    *                            zoom level.
    * @param callback            Optional.  If given, it's asynchronously called
    *                            when done.
    */
   _applySettingToPref: function FullZoom__applySettingToPref(suppressZoomChange, callback) {
+    Services.obs.notifyObservers(null, "browser-fullZoom:zoomChange", "");
+
     if (!this.siteSpecific ||
         gInPrintPreviewMode ||
         content.document.mozSyntheticDocument) {
       this._executeSoon(callback);
       return;
     }
 
     this._cps2.set(gBrowser.currentURI.spec, this.name, ZoomManager.zoom,
@@ -405,16 +407,18 @@ var FullZoom = {
   },
 
   /**
    * Removes from the content prefs store the zoom level of the current browser.
    *
    * @param callback  Optional.  If given, it's asynchronously called when done.
    */
   _removePref: function FullZoom__removePref(callback) {
+    Services.obs.notifyObservers(null, "browser-fullZoom:zoomReset", "");
+
     if (content.document.mozSyntheticDocument) {
       this._executeSoon(callback);
       return;
     }
     let ctxt = this._loadContextFromWindow(gBrowser.contentWindow);
     this._cps2.removeByDomainAndName(gBrowser.currentURI.spec, this.name, ctxt, {
       handleCompletion: function () {
         if (callback)
--- 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,30 @@
 searchbar {
   -moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
 }
 
 browser[remote="true"] {
   -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
 }
 
+toolbar[customizable="true"] {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar");
+}
+
+%ifdef XP_MACOSX
+toolbar[customizable="true"]:not([nowindowdrag="true"]) {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
+}
+%endif
+
+#toolbar-menubar[autohide="true"] {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-autohide");
+}
+
 tabbrowser {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser");
 }
 
 .tabbrowser-tabs {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tabs");
 }
 
@@ -34,31 +48,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;
 }
@@ -112,114 +126,100 @@ 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;
 }
 
 #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
 #main-window[inFullscreen="true"] {
   padding-top: 0; /* override drawintitlebar="true" */
 }
 %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);
@@ -432,24 +432,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;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -86,16 +86,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:blank",
   "about:newtab",
   "about:home",
   "about:privatebrowsing",
   "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
@@ -931,18 +938,18 @@ var gBrowserInit = {
       // 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();
@@ -1026,17 +1033,23 @@ var gBrowserInit = {
     Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
     Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
     Services.obs.addObserver(gFormSubmitObserver, "invalidformsubmit", false);
 
     BrowserOffline.init();
     OfflineApps.init();
     IndexedDBPromptHelper.init();
     gFormSubmitObserver.init();
+    // Initialize the full zoom setting.
+    // We do this before the session restore service gets initialized so we can
+    // apply full zoom settings to tabs restored by the session restore service.
+    FullZoom.init();
+    PanelUI.init();
     SocialUI.init();
+    LightweightThemeListener.init();
     AddonManager.addAddonListener(AddonsMgrListener);
     WebrtcIndicator.init();
 
     // Ensure login manager is up and running.
     Services.logins;
 
     if (mustLoadSidebar) {
       let sidebar = document.getElementById("sidebar");
@@ -1073,21 +1086,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)
@@ -1221,56 +1229,35 @@ 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);
+
+    gCustomizeMode.init();
+
     // 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);
     }
@@ -1373,16 +1360,19 @@ var gBrowserInit = {
 #endif
 #endif
 
       BrowserOffline.uninit();
       OfflineApps.uninit();
       IndexedDBPromptHelper.uninit();
       AddonManager.removeAddonListener(AddonsMgrListener);
       SocialUI.uninit();
+      LightweightThemeListener.uninit();
+      gCustomizeMode.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
@@ -2657,18 +2647,18 @@ 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");
@@ -3323,129 +3313,23 @@ 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;
@@ -3499,33 +3383,26 @@ 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;
 
   // 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();
@@ -3548,44 +3425,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.
@@ -3606,18 +3468,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;
@@ -3897,27 +3759,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"),
@@ -3984,22 +3835,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,
@@ -4167,18 +4014,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");
       }
     }
@@ -4493,18 +4339,16 @@ function onViewToolbarsPopupShowing(aEve
       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);
     }
   }
@@ -4523,18 +4367,18 @@ function setToolbarVisibility(toolbar, i
 
   toolbar.setAttribute(hidingAttribute, !isVisible);
   document.persist(toolbar.id, hidingAttribute);
 
   PlacesToolbarHelper.init();
   BookmarkingUI.onToolbarVisibilityChange();
   gBrowser.updateWindowResizers();
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-  updateAppButtonDisplay();
+#ifdef CAN_DRAW_IN_TITLEBAR
+  updateTitlebarDisplay();
 #endif
 }
 
 var TabsOnTop = {
   init: function TabsOnTop_init() {
     Services.prefs.addObserver(this._prefName, this, false);
 
     // Only show the toggle UI if the user disabled tabs on top.
@@ -4585,143 +4429,238 @@ var TabsOnTop = {
 }
 
 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
@@ -6802,39 +6741,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;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -4,39 +4,43 @@
 #
 # 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"
@@ -427,39 +431,37 @@
         <separator/>
         <description id="mixed-content-blocked-moreinfo">&mixedContentBlocked.moreinfo;</description>
         <separator/>
         <label id="mixed-content-blocked-helplink" class="text-link"
                value="&mixedContentBlocked.helplink;"/>
       </popupnotificationcontent>
     </popupnotification>
 
+#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"
@@ -477,169 +479,395 @@
              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"
+#ifdef XP_MACOSX
+            ordinal="0"
+#else
+            ordinal="1000"
+#endif
+      />
+
+#ifdef XP_MACOSX
+      <hbox class="titlebar-placeholder" type="fullscreen-button" ordinal="1000"/>
+#endif
 #endif
     </toolbar>
 
     <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"
+             customizationtarget="nav-bar-customizationtarget"
              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"
+      <hbox id="nav-bar-customizationtarget" class="customization-target" flex="0">
+        <toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
+                     context="backForwardMenu" removable="false"
+                     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>
+
+        <toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true"
+                     title="&locationItem.title;" class="chromeclass-location" removable="false">
+          <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="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="reload-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       label="&reloadCmd.label;" removable="true"
+                       command="Browser:ReloadOrDuplicate"
                        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>
+                       tooltiptext="&reloadButton.tooltip;"/>
+
+        <toolbarbutton id="stop-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       label="&stopCmd.label;" removable="true"
+                       command="Browser:Stop"
+                       tooltiptext="&stopButton.tooltip;"/>
+
+        <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="social-share-button"
+                       class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       hidden="true"
+                       label="&sharePageCmd.label;"
+                       tooltiptext="&sharePageCmd.label;"
+                       command="Social:SharePage"/>
+
+        <toolbaritem id="social-toolbar-item"
+                     class="chromeclass-toolbar-additional"
+                     removable="false"
+                     title="&socialToolbar.title;"
+                     hidden="true"
+                     skipintoolbarset="true"
+                     observes="socialActiveBroadcaster">
+          <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"
+                         observes="socialBroadcaster_userDetails"/>
+                </vbox>
+              </menuitem>
+#ifndef XP_WIN
+              <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"
+                         class="toolbarbutton-1"
+                         hidden="true"
+                         disabled="true"
+                         command="Social:TogglePageMark"/>
+        </toolbaritem>
+      </hbox>
+
+      <toolbaritem id="PanelUI-button"
+                   class="chromeclass-toolbar-additional"
+                   removable="false"
+                   title="&appmenu.title;">
+        <toolbarbutton id="PanelUI-menu-button"
+                       class="toolbarbutton-1"
+                       label="&brandShortName;"
+                       tooltiptext="&appmenu.title;"
+                       oncommand="PanelUI.toggle(event);"/>
       </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"/>
+      <hbox id="window-controls" hidden="true" pack="end">
+        <toolbarbutton id="minimize-button"
+                       tooltiptext="&fullScreenMinimize.tooltip;"
+                       oncommand="window.minimize();"/>
+
+        <toolbarbutton id="restore-button"
+                       tooltiptext="&fullScreenRestore.tooltip;"
+                       oncommand="BrowserFullScreen();"/>
+
+        <toolbarbutton id="close-button"
+                       tooltiptext="&fullScreenClose.tooltip;"
+                       oncommand="BrowserTryToCloseWindow();"/>
+      </hbox>
+    </toolbar>
+
+    <toolbarset id="customToolbars" context="toolbar-context-menu"/>
+
+    <toolbar id="PersonalToolbar"
+             mode="icons" iconsize="small" defaulticonsize="small"
+             lockiconsize="true"
+             class="chromeclass-directories"
+             context="toolbar-context-menu"
+             defaultset="personal-bookmarks"
+             toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;"
+             collapsed="true"
+             customizable="true">
+      <toolbaritem flex="1" id="personal-bookmarks" title="&bookmarksItem.title;"
+                   removable="true">
+        <hbox flex="1"
+              id="PlacesToolbar"
+              context="placesContext"
+              onclick="BookmarksEventHandler.onClick(event, this._placesView);"
+              oncommand="BookmarksEventHandler.onCommand(event, this._placesView);"
+              tooltip="bhTooltip"
+              popupsinherittooltip="true">
+          <toolbarbutton class="bookmark-item bookmarks-toolbar-customize"
+                         mousethrough="never"
+                         label="&bookmarksToolbarItem.label;"/>
+          <hbox flex="1">
+            <hbox align="center">
+              <image id="PlacesToolbarDropIndicator"
+                     mousethrough="always"
+                     collapsed="true"/>
             </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);"/>
+            <scrollbox orient="horizontal"
+                       id="PlacesToolbarItems"
+                       flex="1"/>
+            <toolbarbutton type="menu"
+                           id="PlacesChevron"
+                           class="chevron"
+                           mousethrough="never"
+                           collapsed="true"
+                           tooltiptext="&bookmarksToolbarChevron.tooltip;"
+                           onpopupshowing="document.getElementById('PlacesToolbar')
+                                                   ._placesView._onChevronPopupShowing(event);">
+              <menupopup id="PlacesChevronPopup"
+                         placespopup="true"
+                         tooltip="bhTooltip" popupsinherittooltip="true"
+                         context="placesContext"/>
+            </toolbarbutton>
           </hbox>
-          <toolbarbutton id="urlbar-go-button"
-                         class="chromeclass-toolbar-additional"
-                         onclick="gURLBar.handleCommand(event);"
-                         tooltiptext="&goEndCap.tooltip;"/>
-          <toolbarbutton id="urlbar-reload-button"
-                         class="chromeclass-toolbar-additional"
-                         command="Browser:ReloadOrDuplicate"
-                         onclick="checkForMiddleClick(this, event);"
-                         tooltiptext="&reloadButton.tooltip;"/>
-          <toolbarbutton id="urlbar-stop-button"
-                         class="chromeclass-toolbar-additional"
-                         command="Browser:Stop"
-                         tooltiptext="&stopButton.tooltip;"/>
-        </textbox>
+        </hbox>
       </toolbaritem>
+    </toolbar>
 
-      <toolbarbutton id="reload-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&reloadCmd.label;" removable="true"
-                     command="Browser:ReloadOrDuplicate"
+    <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="&reloadButton.tooltip;"/>
+                     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="stop-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&stopCmd.label;" removable="true"
-                     command="Browser:Stop"
-                     tooltiptext="&stopButton.tooltip;"/>
+      <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="caption-buttons"
+#ifdef XP_MACOSX
+            ordinal="0"
+#else
+            ordinal="1000"
+#endif
+      />
+
+#ifdef XP_MACOSX
+      <hbox class="titlebar-placeholder" type="fullscreen-button"
+            ordinal="1000"/>
+#endif
+#endif
+    </toolbar>
+
+    <toolbarpalette id="BrowserToolbarPalette">
+
+# Update primaryToolbarButtons in browser/themes/shared/browser.inc when adding
+# or removing default items with the toolbarbutton-1 class.
 
       <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="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);"
@@ -722,233 +950,23 @@
                      label="&homeButton.label;"
                      ondragover="homeButtonObserver.onDragOver(event)"
                      ondragenter="homeButtonObserver.onDragOver(event)"
                      ondrop="homeButtonObserver.onDrop(event)"
                      ondragexit="homeButtonObserver.onDragExit(event)"
                      onclick="BrowserGoHome(event);"
                      aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
 
-      <toolbarbutton id="social-share-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     hidden="true"
-                     label="&sharePageCmd.label;"
-                     tooltiptext="&sharePageCmd.label;"
-                     command="Social:SharePage"/>
-
-      <toolbaritem id="social-toolbar-item"
-                   class="chromeclass-toolbar-additional"
-                   removable="false"
-                   title="&socialToolbar.title;"
-                   hidden="true"
-                   skipintoolbarset="true"
-                   observes="socialActiveBroadcaster">
-        <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"
-                       observes="socialBroadcaster_userDetails"/>
-              </vbox>
-            </menuitem>
-#ifndef XP_WIN
-            <menuseparator class="social-statusarea-separator"/>
+      <toolbarbutton id="print-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+#ifdef XP_MACOSX
+                     command="cmd_print"
+#else
+                     command="cmd_printPreview"
 #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"
-                       class="toolbarbutton-1"
-                       hidden="true"
-                       disabled="true"
-                       command="Social:TogglePageMark"/>
-      </toolbaritem>
-
-      <hbox id="window-controls" hidden="true" pack="end">
-        <toolbarbutton id="minimize-button"
-                       tooltiptext="&fullScreenMinimize.tooltip;"
-                       oncommand="window.minimize();"/>
-
-        <toolbarbutton id="restore-button"
-                       tooltiptext="&fullScreenRestore.tooltip;"
-                       oncommand="BrowserFullScreen();"/>
-
-        <toolbarbutton id="close-button"
-                       tooltiptext="&fullScreenClose.tooltip;"
-                       oncommand="BrowserTryToCloseWindow();"/>
-      </hbox>
-    </toolbar>
-
-    <toolbarset id="customToolbars" context="toolbar-context-menu"/>
-
-    <toolbar id="PersonalToolbar"
-             mode="icons" iconsize="small" defaulticonsize="small"
-             lockiconsize="true"
-             class="chromeclass-directories"
-             context="toolbar-context-menu"
-             defaultset="personal-bookmarks"
-             toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;"
-             collapsed="true"
-             customizable="true">
-      <toolbaritem flex="1" id="personal-bookmarks" title="&bookmarksItem.title;"
-                   removable="true">
-        <hbox flex="1"
-              id="PlacesToolbar"
-              context="placesContext"
-              onclick="BookmarksEventHandler.onClick(event, this._placesView);"
-              oncommand="BookmarksEventHandler.onCommand(event, this._placesView);"
-              tooltip="bhTooltip"
-              popupsinherittooltip="true">
-          <toolbarbutton class="bookmark-item bookmarks-toolbar-customize"
-                         mousethrough="never"
-                         label="&bookmarksToolbarItem.label;"/>
-          <hbox flex="1">
-            <hbox align="center">
-              <image id="PlacesToolbarDropIndicator"
-                     mousethrough="always"
-                     collapsed="true"/>
-            </hbox>
-            <scrollbox orient="horizontal"
-                       id="PlacesToolbarItems"
-                       flex="1"/>
-            <toolbarbutton type="menu"
-                           id="PlacesChevron"
-                           class="chevron"
-                           mousethrough="never"
-                           collapsed="true"
-                           tooltiptext="&bookmarksToolbarChevron.tooltip;"
-                           onpopupshowing="document.getElementById('PlacesToolbar')
-                                                   ._placesView._onChevronPopupShowing(event);">
-              <menupopup id="PlacesChevronPopup"
-                         placespopup="true"
-                         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
-    </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;"/>
+                     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);"
@@ -1041,55 +1059,59 @@
                      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" 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"
-               flex="1"
-               style="min-width: 14em; width: 18em; max-width: 36em;"/>
-    </vbox>
-    <vbox id="browser-border-end" hidden="true" layer="true"/>
-  </hbox>
+      <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"
+                 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;"/>
@@ -1140,57 +1162,52 @@
     <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.0645 C 0.5683,0.0679,0.51693,0.3764,0.4837,0.5484 c -0.0522,0.2702,-0.1425,0.4194,-0.4333,0.4194 L 0,1 H 1.0333 V 0.0645 z"/>
+    </svg:clipPath>
+    <svg:clipPath id="tab-curve-clip-path-end" clipPathUnits="objectBoundingBox">
+      <svg:path d="M -0.0333,0.0645 C 0.4317,0.0679,0.4831,0.3764,0.5163,0.5484 c 0.0522,0.2702,+0.1425,0.4194,0.4333,0.4194 L 1,1 H -0.033 V 0.0645 z"/>
+    </svg:clipPath>
+    <svg:clipPath id="tab-clip-path-outer" clipPathUnits="objectBoundingBox">
+      <svg:path d="m 0.2197,0 0,0.4264 c -0.0156,0.1238 -0.0201,0.2548 -0.0492,0.3730 C 0.1464,0.9030 0.0889,0.9397 0.0379,0.9355 L 0,1 1,1 0.9621,0.9355 c -0.0511,0.0042 -0.1085,-0.0322 -0.1326,-0.1361 -0.0292,-0.1152 -0.0334,-0.2486 -0.0492,-0.3730 L 0.7803,0 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: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/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
@@ -3479,19 +3479,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;
               }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -133,19 +133,17 @@ endif
                  browser_bug585830.js \
                  browser_bug590206.js \
                  browser_bug592338.js \
                  browser_bug594131.js \
                  browser_bug595507.js \
                  browser_bug596687.js \
                  browser_bug597218.js \
                  browser_bug598923.js \
-                 browser_bug599325.js \
                  browser_bug609700.js \
-                 browser_bug616836.js \
                  browser_bug623155.js \
                  browser_bug623893.js \
                  browser_bug624734.js \
                  browser_bug647886.js \
                  browser_bug655584.js \
                  browser_bug664672.js \
                  browser_bug678392.js \
                  browser_bug678392-1.html \
@@ -163,24 +161,22 @@ endif
                  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 \
@@ -237,17 +233,16 @@ endif
                  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 \
--- a/browser/base/content/test/browser_addon_bar.js
+++ b/browser/base/content/test/browser_addon_bar.js
@@ -8,19 +8,18 @@ function test() {
   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;
+    // open the toolbars menu
+    toolbarMenu = 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);
@@ -49,15 +48,14 @@ function test() {
   }
 
   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");
+  // open the view menu
+  topMenu = 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_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");
-}
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
@@ -1489,130 +1489,16 @@
         });
         if (item != null) {
           item.setAttribute("padbottom", "true");
         }
       ]]></constructor>
     </implementation>
   </binding>
 
-  <binding id="splitmenu">
-    <content>
-      <xul:hbox anonid="menuitem" flex="1"
-                class="splitmenu-menuitem"
-                xbl:inherits="iconic,label,disabled,onclick=oncommand,_moz-menuactive=active"/>
-      <xul:menu anonid="menu" class="splitmenu-menu"
-                xbl:inherits="disabled,_moz-menuactive=active"
-                oncommand="event.stopPropagation();">
-        <children includes="menupopup"/>
-      </xul:menu>
-    </content>
-
-    <implementation implements="nsIDOMEventListener">
-      <constructor><![CDATA[
-        this._parentMenupopup.addEventListener("DOMMenuItemActive", this, false);
-        this._parentMenupopup.addEventListener("popuphidden", this, false);
-      ]]></constructor>
-
-      <destructor><![CDATA[
-        this._parentMenupopup.removeEventListener("DOMMenuItemActive", this, false);
-        this._parentMenupopup.removeEventListener("popuphidden", this, false);
-      ]]></destructor>
-
-      <field name="menuitem" readonly="true">
-        document.getAnonymousElementByAttribute(this, "anonid", "menuitem");
-      </field>
-      <field name="menu" readonly="true">
-        document.getAnonymousElementByAttribute(this, "anonid", "menu");
-      </field>
-
-      <field name="_menuDelay">600</field>
-
-      <field name="_parentMenupopup"><![CDATA[
-        this._getParentMenupopup(this);
-      ]]></field>
-
-      <method name="_getParentMenupopup">
-        <parameter name="aNode"/>
-        <body><![CDATA[
-          let node = aNode.parentNode;
-          while (node) {
-            if (node.localName == "menupopup")
-              break;
-            node = node.parentNode;
-          }
-          return node;
-        ]]></body>
-      </method>
-
-      <method name="handleEvent">
-        <parameter name="event"/>
-        <body><![CDATA[
-          switch (event.type) {
-            case "DOMMenuItemActive":
-              if (this.getAttribute("active") == "true" &&
-                  event.target != this &&
-                  this._getParentMenupopup(event.target) == this._parentMenupopup)
-                this.removeAttribute("active");
-              break;
-            case "popuphidden":
-              if (event.target == this._parentMenupopup)
-                this.removeAttribute("active");
-              break;
-          }
-        ]]></body>
-      </method>
-    </implementation>
-
-    <handlers>
-      <handler event="mouseover"><![CDATA[
-        if (this.getAttribute("active") != "true") {
-          this.setAttribute("active", "true");
-
-          let event = document.createEvent("Events");
-          event.initEvent("DOMMenuItemActive", true, false);
-          this.dispatchEvent(event);
-
-          if (this.getAttribute("disabled") != "true") {
-            let self = this;
-            setTimeout(function () {
-              if (self.getAttribute("active") == "true")
-                self.menu.open = true;
-            }, this._menuDelay);
-          }
-        }
-      ]]></handler>
-
-      <handler event="popupshowing"><![CDATA[
-        if (event.target == this.firstChild &&
-            this._parentMenupopup._currentPopup)
-          this._parentMenupopup._currentPopup.hidePopup();
-      ]]></handler>
-
-      <handler event="click" phase="capturing"><![CDATA[
-        if (this.getAttribute("disabled") == "true") {
-          // Prevent the command from being carried out
-          event.stopPropagation();
-          return;
-        }
-
-        let node = event.originalTarget;
-        while (true) {
-          if (node == this.menuitem)
-            break;
-          if (node == this)
-            return;
-          node = node.parentNode;
-        }
-
-        this._parentMenupopup.hidePopup();
-      ]]></handler>
-    </handlers>
-  </binding>
-
   <binding id="menuitem-tooltip" extends="chrome://global/content/bindings/menu.xml#menuitem">
     <implementation>
       <constructor><![CDATA[
         this.setAttribute("tooltiptext", this.getAttribute("acceltext"));
         // TODO: Simplify this to this.setAttribute("acceltext", "") once bug
         // 592424 is fixed
         document.getAnonymousElementByAttribute(this, "anonid", "accel").firstChild.setAttribute("value", "");
       ]]></constructor>
--- 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
@@ -79,16 +79,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
@@ -102,16 +102,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,30 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+.panel-viewstack[view="main"] > .panel-clickcapturer {
+  pointer-events: none;
+}
+
+.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] {
+  transition: height 150ms;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -0,0 +1,83 @@
+<!-- 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"
+       consumeoutsideclicks="true">
+  <panelmultiview id="PanelUI-multiView">
+    <panelmainview id="PanelUI-mainView">
+      <vbox class="PanelUI-pageControls" pack="center">
+        <hbox class="PanelUI-editControls">
+          <toolbarbutton id="PanelUI-cut-btn" flex="1"
+                         label="&cutCmd.label;"
+                         tooltiptext="&cutButton.tooltip;"
+                         class="panel-combined-button"
+                         command="cmd_cut"/>
+          <toolbarbutton id="PanelUI-copy-btn" flex="1"
+                         label="&copyCmd.label;"
+                         tooltiptext="&copyButton.tooltip;"
+                         class="panel-combined-button"
+                         command="cmd_copy"/>
+          <toolbarbutton id="PanelUI-paste-btn" flex="1"
+                         label="&pasteCmd.label;"
+                         tooltiptext="&pasteButton.tooltip;"
+                         class="panel-combined-button"
+                         command="cmd_paste"/>
+        </hbox>
+        <hbox class="PanelUI-zoomControls">
+          <toolbarbutton id="PanelUI-zoomOut-btn" flex="1"
+                         noautoclose="true" label="&fullZoomReduceCmd.label;"
+                         command="cmd_fullZoomReduce"
+                         class="panel-combined-button"
+                         tooltiptext="&zoomOutButton.tooltip;"/>
+          <toolbarbutton id="PanelUI-zoomReset-btn" flex="1"
+                         noautoclose="true" command="cmd_fullZoomReset"
+                         class="panel-combined-button"
+                         tooltiptext="&zoomReset.tooltip;"/>
+          <toolbarbutton id="PanelUI-zoomIn-btn" flex="1"
+                         noautoclose="true" label="&fullZoomEnlargeCmd.label;"
+                         command="cmd_fullZoomEnlarge"
+                         class="panel-combined-button"
+                         tooltiptext="&zoomInButton.tooltip;"/>
+        </hbox>
+      </vbox>
+
+      <vbox id="PanelUI-contents" type="grid"/>
+
+      <vbox id="PanelUI-mainView-spring" flex="1"/>
+
+      <footer class="PanelUI-footer" align="center">
+        <!-- The parentNode is used so that the footer is presented as the anchor
+             instead of just the button being the anchor. -->
+        <toolbarbutton id="PanelUI-help-btn" label="&helpMenu.label;"
+                       onclick="PanelUI.showHelpView(this.parentNode);"/>
+        <spacer flex="1"/>
+        <toolbarbutton id="PanelUI-customize-btn" label="&appMenuCustomize.label;"
+                       command="cmd_CustomizeToolbars"/>
+      </footer>
+    </panelmainview>
+
+    <panelsubview 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'); PanelUI.hide();"/>
+    </panelsubview>
+
+    <panelsubview id="PanelUI-help" flex="1">
+      <label value="&helpMenu.label;"/>
+      <vbox id="PanelUI-helpItems"/>
+    </panelsubview>
+  </panelmultiview>
+</panel>
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.js
@@ -0,0 +1,255 @@
+/* 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",
+      zoomResetButton: "PanelUI-zoomReset-btn"
+    };
+  },
+
+  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);
+    }
+
+    // Register ourselves with the service so we know when the zoom prefs change.
+    Services.obs.addObserver(this, "browser-fullZoom:zoomChange", false);
+    Services.obs.addObserver(this, "browser-fullZoom:zoomReset", false);
+
+    this._updateZoomResetButton();
+
+    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);
+    Services.obs.removeObserver(this, "browser-fullZoom:zoomChange");
+    Services.obs.removeObserver(this, "browser-fullZoom:zoomReset");
+  },
+
+  /**
+   * 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.
+   */
+  replaceMainView: function(aMainView) {
+    this.multiView.insertBefore(aMainView, this.multiView.firstChild);
+  },
+
+  /**
+   * 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();
+
+      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;
+      }
+    }
+  },
+
+  /**
+   * nsIObserver implementation, responding to zoom pref changes
+   */
+  observe: function (aSubject, aTopic, aData) {
+    this._updateZoomResetButton();
+  },
+
+  /**
+   * 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.
+   */
+  ensureRegistered: function() {
+    CustomizableUI.registerMenuPanel(this.contents);
+  },
+
+  /**
+   * 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);
+
+      let tempPanel = document.createElement("panel");
+      tempPanel.appendChild(viewNode);
+      tempPanel.setAttribute("type", "arrow");
+      tempPanel.setAttribute("id", "customizationui-widget-panel");
+      document.getElementById(CustomizableUI.AREA_NAVBAR).appendChild(tempPanel);
+      tempPanel.addEventListener("popuphidden", function panelRemover() {
+        tempPanel.removeEventListener("popuphidden", panelRemover);
+        this.multiView.appendChild(viewNode);
+        tempPanel.parentElement.removeChild(tempPanel);
+      }.bind(this));
+
+      tempPanel.openPopup(aAnchor, "bottomcenter topright");
+    }
+  },
+
+  /**
+   * 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";
+  },
+
+  _updateZoomResetButton: function() {
+    this.zoomResetButton.setAttribute("label", gNavigatorBundle
+      .getFormattedString("zoomReset.label", [Math.floor(ZoomManager.zoom * 100)]));
+  },
+
+  // Button onclick handler which hides the whole PanelUI
+  _onHelpViewClick: function(aEvent) {
+    if (aEvent.button == 0 && !aEvent.target.hasAttribute("disabled")) {
+      PanelUI.hide();
+    }
+  },
+
+  _onHelpViewShow: function(aEvent) {
+    // Call global menu setup function
+    buildHelpMenu();
+
+    let helpMenu = document.getElementById("menu_HelpPopup");
+    let items = this.getElementsByTagName("vbox")[0];
+    let attrs = ["oncommand", "onclick", "label", "key", "disabled"];
+    let NSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+    // Remove all buttons from the view
+    while (items.firstChild) {
+      items.removeChild(items.firstChild);
+    }
+
+    // Add the current set of menuitems of the Help menu to this view
+    let menuItems = Array.prototype.slice.call(helpMenu.getElementsByTagName("menuitem"));
+    let fragment = document.createDocumentFragment();
+    for (let node of menuItems) {
+      if (node.hidden)
+        continue;
+      let button = document.createElementNS(NSXUL, "toolbarbutton");
+      // Copy specific attributes from a menuitem of the Help menu
+      for (let attrName of attrs) {
+        if (!node.hasAttribute(attrName))
+          continue;
+        button.setAttribute(attrName, node.getAttribute(attrName));
+      }
+      fragment.appendChild(button);
+    }
+    items.appendChild(fragment);
+
+    this.addEventListener("click", PanelUI._onHelpViewClick, false);
+  },
+
+  _onHelpViewHide: function(aEvent) {
+    this.removeEventListener("click", PanelUI._onHelpViewClick);
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.xml
@@ -0,0 +1,236 @@
+<?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">
+        <xul:stack anonid="viewStack" view="main" class="panel-viewstack">
+          <children includes="panelmainview"/>
+
+          <!-- 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="panelsubview"/>
+          </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="_mainView" readonly="true">
+        this.querySelector("panelmainview");
+      </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>
+
+      <property name="showingSubView" readonly="true"
+                onget="return this._viewStack.getAttribute('view') == 'subview'"/>
+
+      <constructor><![CDATA[
+        this._clickCapturer.addEventListener("click", this);
+        this._panel.addEventListener("popupshowing", this);
+        this._panel.addEventListener("popuphidden", 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._subViews.addEventListener("overflow", this);
+      ]]></constructor>
+
+      <destructor><![CDATA[
+        this._subViewObserver.disconnect();
+        this._panel.removeEventListener("popupshowing", this);
+        this._panel.removeEventListener("popuphidden", this);
+        this._clickCapturer.removeEventListener("click", this);
+      ]]></destructor>
+
+      <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._viewContainer.style.height = this._mainViewHeight + "px";
+            this._subViewObserver.disconnect();
+
+            this._viewStack.setAttribute("view", "main");
+          }
+
+          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);
+
+          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._viewStack.setAttribute("view", "subview");
+          this._shiftMainView(aAnchor);
+
+          this._mainViewHeight = this._viewStack.clientHeight;
+          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._mainView.getBoundingClientRect();
+            let leftEdge = anchorRect.left - mainViewRect.left;
+            let center = aAnchor.clientWidth / 2;
+            let target = leftEdge + center;
+            this._mainView.style.transform = "translateX(-" + target + "px)";
+            aAnchor.classList.add("panel-multiview-anchor");
+          } else {
+            this._mainView.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 subview on the next tick.
+              setTimeout(this._syncContainerWithSubView.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[
+          this._viewContainer.style.height = this._subViews.scrollHeight + "px";
+        ]]></body>
+      </method>
+      <method name="_syncContainerWithMainView">
+        <body><![CDATA[
+          this._viewContainer.style.height = this._mainView.scrollHeight + "px";
+        ]]></body>
+      </method>
+
+    </implementation>
+  </binding>
+
+</bindings>
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/content/toolbar.xml
@@ -0,0 +1,265 @@
+<?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 = this;
+
+          return this._customizationTarget;
+        ]]></getter>
+      </property>
+
+      <property name="toolbox" readonly="true">
+        <getter><![CDATA[
+          if (this._toolbox)
+            return this._toolbox;
+
+          let toolboxId = this.getAttribute("toolboxid");
+          if (toolboxId) {
+            let toolbox = document.getElementById(toolboxId);
+            if (toolbox) {
+              if (toolbox.externalToolbars.indexOf(this) == -1)
+                toolbox.externalToolbars.push(this);
+
+              this._toolbox = toolbox;
+            }
+          }
+
+          if (!this._toolbox && this.parentNode &&
+              this.parentNode.localName == "toolbox") {
+            this._toolbox = this.parentNode;
+          }
+
+          return this._toolbox;
+        ]]></getter>
+      </property>
+
+      <property name="currentSet" readonly="true">
+        <getter><![CDATA[
+          if (!this._customizationTarget)
+            return "";
+
+          return [node.id for (node of this._customizationTarget.children)].join(',');
+        ]]></getter>
+      </property>
+
+
+    </implementation>
+  </binding>
+
+  <!-- The toolbar-menubar-autohide and toolbar-drag bindings are almost
+       verbatim copies of their toolkit counterparts - they just inherit from
+       the customizableui's toolbar binding instead of toolkit's. We're currently
+       OK with the maintainance burden of having two copies of a binding, since
+       the long term goal is to move the customization framework into toolkit. -->
+
+  <binding id="toolbar-menubar-autohide"
+           extends="chrome://browser/content/customizableui/toolbar.xml#toolbar">
+    <implementation>
+      <constructor>
+        this._setInactive();
+      </constructor>
+
+      <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>
+</bindings>
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/moz.build
@@ -0,0 +1,10 @@
+# -*- 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',
+]
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -0,0 +1,1754 @@
+/* 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");
+
+const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+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();
+
+/**
+ * If the user does not have any state saved, this is the default set of
+ * placements to use.
+ */
+let gDefaultPlacements = new Map([
+  ["toolbar-menubar", [
+    "menubar-items",
+  ]],
+  ["TabsToolbar", [
+    "tabbrowser-tabs",
+    "new-tab-button",
+    "alltabs-button",
+    "tabs-closebutton"
+  ]],
+  ["nav-bar", [
+    "unified-back-forward-button",
+    "urlbar-container",
+    "reload-button",
+    "stop-button",
+    "search-container",
+    "webrtc-status-button",
+    "bookmarks-menu-button",
+    "downloads-button",
+    "home-button",
+    "social-toolbar-button",
+  ]],
+  ["PersonalToolbar", [
+    "personal-bookmarks",
+  ]],
+  ["PanelUI-contents", [
+    "new-window-button",
+    "privatebrowsing-button",
+    "save-page-button",
+    "print-button",
+    "history-panelmenu",
+    "fullscreen-button",
+    "find-button",
+    "preferences-button",
+    "add-ons-button"
+  ]]
+]);
+
+//XXXunf Temporary. Need a nice way to abstract functions to build widgets
+//       of these types.
+let gSupportedWidgetTypes = new Set(["button", "view"]);
+
+/**
+ * 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;
+
+/**
+ * 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 gDebug = false;
+try {
+  gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
+} catch (e) {}
+
+function LOG(aMsg) {
+  if (gDebug) {
+    Services.console.logStringMessage("[CustomizableUI] " + aMsg);
+  }
+}
+function ERROR(aMsg) Cu.reportError("[CustomizableUI] " + aMsg);
+
+
+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
+    });
+    this.registerArea(CustomizableUI.AREA_NAVBAR, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR
+    });
+    this.registerArea(CustomizableUI.AREA_MENUBAR, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR
+    });
+    this.registerArea(CustomizableUI.AREA_TABSTRIP, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR
+    });
+    this.registerArea(CustomizableUI.AREA_BOOKMARKS, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR
+    });
+  },
+
+  _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) {
+      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);
+    }
+  },
+
+  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);
+    }
+
+    this.registerBuildArea(area, aToolbar);
+
+    let placements = gPlacements.get(area);
+    this.buildArea(area, placements, aToolbar);
+    aToolbar.setAttribute("currentset", placements.join(","));
+  },
+
+  buildArea: function(aArea, aPlacements, aAreaNode) {
+    let document = aAreaNode.ownerDocument;
+    let window = document.defaultView;
+    let container = aAreaNode.customizationTarget;
+
+    if (!container) {
+      throw new Error("Expected area " + aArea
+                      + " to have a customizationTarget attribute.");
+    }
+
+    this.beginBatchUpdate();
+
+    let currentNode = container.firstChild;
+    for (let id of aPlacements) {
+      if (currentNode && currentNode.id == id) {
+        this._addParentFlex(currentNode);
+        this.setLocationAttributes(currentNode, container, aArea);
+
+        // Normalize removable attribute. It defaults to false if the widget is
+        // originally defined as a child of a build area.
+        if (!currentNode.hasAttribute("removable")) {
+          currentNode.setAttribute("removable", false);
+        }
+
+        currentNode = currentNode.nextSibling;
+        continue;
+      }
+
+      let [provider, node] = this.getWidgetNode(id, window);
+      if (!node) {
+        LOG("Unknown widget: " + id);
+        continue;
+      }
+
+      if (provider == CustomizableUI.PROVIDER_XUL &&
+          aArea == CustomizableUI.AREA_PANEL) {
+        this.ensureButtonClosesPanel(node);
+      }
+      this.insertWidgetBefore(node, currentNode, container, aArea);
+      this._addParentFlex(node);
+    }
+
+    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 (node.getAttribute("removable") == "true") {
+            if (palette) {
+              palette.appendChild(node);
+            } else {
+              container.removeChild(node);
+            }
+          } else {
+            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();
+  },
+
+  ensureButtonClosesPanel: function(aNode) {
+    //XXXunf This seems kinda hacky, but I can't find any other reliable method.
+    //XXXunf Is it worth going to the effort to remove these when appropriate?
+    // The "command" event only gets fired if there's not an attached command
+    // (via the "command" attribute). For menus, this is handled natively, but
+    // since the panel isn't implemented as a menu, we have to handle it
+    // ourselves.
+
+    aNode.addEventListener("mouseup", this.maybeAutoHidePanel, false);
+    aNode.addEventListener("keypress", this.maybeAutoHidePanel, false);
+  },
+
+  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)) {
+      return [ CustomizableUI.PROVIDER_SPECIAL,
+               this.createSpecialWidget(aWidgetId, document) ];
+    }
+
+    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")) {
+      if (!btn.hasAttribute("noautoclose")) {
+        this.ensureButtonClosesPanel(btn);
+      }
+    }
+
+    aPanel.toolbox = document.getElementById("navigator-toolbox");
+    aPanel.customizationTarget = 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) {
+      Cu.reportError("Could not find any placements for " + aArea +
+                     " when adding a widget.");
+      return;
+    }
+
+    let nextNodeId = placements[aPosition + 1];
+
+    // Go through each of the nodes associated with this area and move the
+    // widget to the requested location.
+    for (let areaNode of areaNodes) {
+      let window = areaNode.ownerDocument.defaultView;
+      let container = areaNode.customizationTarget;
+      let [provider, widgetNode] = this.getWidgetNode(aWidgetId, window);
+
+      if (provider == CustomizableUI.PROVIDER_XUL &&
+          aArea == CustomizableUI.AREA_PANEL) {
+        this.ensureButtonClosesPanel(widgetNode);
+      }
+
+      let nextNode = nextNodeId ? container.querySelector(idToSelector(nextNodeId))
+                                : null;
+      this.insertWidgetBefore(widgetNode, nextNode, container, aArea);
+      this._addParentFlex(widgetNode);
+    }
+  },
+
+  onWidgetRemoved: function(aWidgetId, aArea) {
+    let areaNodes = gBuildAreas.get(aArea);
+    if (!areaNodes) {
+      return;
+    }
+
+    for (let areaNode of areaNodes) {
+      let container = areaNode.customizationTarget;
+      let widgetNode = container.ownerDocument.getElementById(aWidgetId);
+      if (!widgetNode) {
+        ERROR("Widget not found, unable to remove");
+        continue;
+      }
+
+      this._removeParentFlex(widgetNode);
+
+      if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
+        container.removeChild(widgetNode);
+      } else {
+        this.removeLocationAttributes(widgetNode);
+        areaNode.toolbox.palette.appendChild(widgetNode);
+      }
+    }
+  },
+
+  onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) {
+    let areaNodes = gBuildAreas.get(aArea);
+    if (!areaNodes) {
+      return;
+    }
+
+    let placements = gPlacements.get(aArea);
+    if (!placements) {
+      Cu.reportError("Could not find any placements for " + aArea +
+                     " when moving a widget.");
+      return;
+    }
+
+    let nextNodeId = placements[aNewPosition + 1];
+
+    for (let areaNode of areaNodes) {
+      let window = areaNode.ownerDocument.defaultView;
+      let container = areaNode.customizationTarget;
+      let [provider, widgetNode] = this.getWidgetNode(aWidgetId, window);
+      if (!widgetNode) {
+        ERROR("Widget not found, unable to move");
+        continue;
+      }
+
+      let nextNode = nextNodeId ? container.querySelector(idToSelector(nextNodeId))
+                                : null;
+      this.insertWidgetBefore(widgetNode, nextNode, container, aArea);
+    }
+  },
+
+  isBuildAreaRegistered: function(aArea, aInstance) {
+    if (!gBuildAreas.has(aArea)) {
+      return false;
+    }
+    return gBuildAreas.get(aArea).has(aInstance);
+  },
+
+  registerBuildArea: function(aArea, aNode) {
+    // We ensure that the window is registered to have its customization data
+    // cleaned up when unloading.
+    let window = aNode.ownerDocument.defaultView;
+    this.registerBuildWindow(window);
+
+    // Also register this build area's toolbox.
+    if (aNode.toolbox) {
+      gBuildWindows.get(window).add(aNode.toolbox);
+    }
+
+    if (!gBuildAreas.has(aArea)) {
+      gBuildAreas.set(aArea, new Set());
+    }
+
+    gBuildAreas.get(aArea).add(aNode);
+  },
+
+  registerBuildWindow: function(aWindow) {
+    if (!gBuildWindows.has(aWindow)) {
+      gBuildWindows.set(aWindow, new Set());
+    }
+
+    aWindow.addEventListener("unload", this, false);
+  },
+
+  unregisterBuildWindow: function(aWindow) {
+    gBuildWindows.delete(aWindow);
+    let document = aWindow.document;
+
+    for (let [, area] of gBuildAreas) {
+      for (let node of area) {
+        if (node.ownerDocument == document) {
+          area.delete(node);
+        }
+      }
+    }
+
+    for (let [,widget] of gPalette)
+      widget.instances.delete(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 "unload": {
+        let window = aEvent.currentTarget;
+        window.removeEventListener("unload", this);
+        this.unregisterBuildWindow(window);
+        break;
+      }
+    }
+  },
+
+  isSpecialWidget: function(aId) {
+    //XXXunf Need to double check these are getting handled correctly
+    //       everywhere, notably save/restore.
+    return (aId.startsWith("separator") ||
+            aId.startsWith("spring") ||
+            aId.startsWith("spacer"));
+  },
+
+  createSpecialWidget: function(aId, aDocument) {
+    let node = aDocument.createElementNS(kNSXUL, "toolbar" + 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.
+    node.id = aId + Date.now() + (++gNewElementCount);
+    if (aId == "spring") {
+      node.flex = 1;
+    }
+    return node;
+  },
+
+  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);
+
+    let 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("label", aWidget.name);
+    node.setAttribute("tooltiptext", aWidget.description);
+    //XXXunf Need to hook this up to a <key> element or something.
+    if (aWidget.shortcut) {
+      node.setAttribute("acceltext", aWidget.shortcut);
+    }
+    node.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional");
+
+    let handler = this.handleWidgetClick.bind(this, aWidget, node);
+    node.addEventListener("command", handler, 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.");
+    }
+
+    aWidget.instances.set(aDocument, node);
+    return node;
+  },
+
+  handleWidgetClick: function(aWidget, aNode, aEvent) {
+    LOG("handleWidgetClick");
+
+    if (aWidget.type == "button") {
+      this.maybeAutoHidePanel(aEvent);
+
+      if (aWidget.onCommand) {
+        try {
+          aWidget.onCommand.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);
+      }
+    } else if (aWidget.type == "view") {
+      let ownerWindow = aNode.ownerDocument.defaultView;
+      ownerWindow.PanelUI.showSubView(aWidget.viewId, aNode,
+                                      this.getPlacementOfWidget(aNode.id).area);
+    }
+  },
+
+  maybeAutoHidePanel: function(aEvent) {
+    if (aEvent.type == "keypress" && 
+        !(aEvent.keyCode == aEvent.DOM_VK_ENTER ||
+          aEvent.keyCode == aEvent.DOM_VK_RETURN)) {
+      return;
+    }
+
+    if (aEvent.type == "mouseup" && aEvent.button != 0) {
+      return;
+    }
+
+    let ownerWindow = aEvent.target.ownerDocument.defaultView;
+    ownerWindow.PanelUI.hide();
+  },
+
+  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 [i for (i of widgets)];
+  },
+
+  getPlacementOfWidget: function(aWidgetId) {
+    let widget = gPalette.get(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).set(aWidgetId);
+      return;
+    }
+
+    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);
+    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");
+      if (gDefaultPlacements.has(aArea)) {
+        let defaults = gDefaultPlacements.get(aArea);
+        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 [i for (i of 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) {
+        Cu.reportError(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 = widget.defaultArea;
+      if (gDefaultPlacements.has(area)) {
+        gDefaultPlacements.get(area).push(widget.id);
+      } else {
+        gDefaultPlacements.set(area, [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).set(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
+    // openned - 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,
+      defaultArea: null,
+      allowedAreas: [],
+      shortcut: null,
+      description: null,
+      icons: {}
+    };
+
+    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", "name"];
+    for (let prop of kReqStringProps) {
+      if (typeof aData[prop] != "string") {
+        return null;
+      }
+      widget[prop] = aData[prop];
+    }
+
+    const kOptStringProps = ["description", "shortcut"];
+    for (let prop of kOptStringProps) {
+      if (typeof aData[prop] == "string") {
+        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;
+
+    if (typeof aData.icons == "object") {
+      let sizes = Object.keys(aData.icons);
+      for (let size of sizes) {
+        if (size == parseInt(size, 10)) {
+          widget.icons[size] = aData.icons[size];
+        }
+      }
+    }
+
+    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;
+    }
+
+    if (gPalette.has(widget.id)) {
+      return null;
+    }
+
+    return widget;
+  },
+
+  destroyWidget: function(aWidgetId) {
+    let widget = gPalette.get(aWidgetId);
+    if (!widget) {
+      return;
+    }
+
+    // This will not remove the widget from gPlacements - we want to keep the
+    // setting so the widget gets put back in it's old position if/when it
+    // returns.
+
+    let area = widget.currentArea;
+    if (area) {
+      let buildArea = gBuildAreas.get(area);
+      for (let buildNode of buildArea) {
+        let widgetNode = buildNode.ownerDocument.getElementById(aWidgetId);
+        if (widgetNode) {
+          widgetNode.parentNode.removeChild(widgetNode);
+        }
+        for (let eventName of kSubviewEvents) {
+          let handler = "on" + eventName;
+          if (typeof widget[handler] == "function") {
+            viewNode.removeEventListener(eventName, widget[handler], false);
+          }
+        }
+      }
+    }
+
+    gPalette.delete(aWidgetId);
+
+    this.notifyListeners("onWidgetDestroyed", aWidgetId);
+  },
+
+  registerManifest: function(aBaseLocation, aData) {
+    let tokens = aData.split(/\s+/);
+    let directive = tokens.shift();
+    if (directive != "widget") {
+      return;
+    }
+
+    for (let [id, widget] of gPalette) {
+      if (widget.source == aBaseLocation.spec) {
+        return; // Already registered.
+      }
+    }
+
+    let uri = NetUtil.newURI(tokens.shift(), null, aBaseLocation);
+
+    dump("\tNew widget! " + uri.spec + "\n");
+
+    let data = "";
+    try {
+      if (uri.schemeIs("jar")) {
+        data = this.readManifestFromJar(uri);
+      } else {
+        data = this.readManifestFromFile(uri);
+      }
+    }
+    catch (e) {
+      Cu.reportError(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() {
+    Services.prefs.clearUserPref(kPrefCustomizationState);
+    LOG("State reset");
+  },
+
+  _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) {
+      //XXXunf Not suppported yet.
+      return true;
+    }
+
+    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, defaultPlacements] of gDefaultPlacements) {
+      let currentPlacements = gPlacements.get(areaId);
+
+      if (currentPlacements.length != defaultPlacements.length) {
+        return false;
+      }
+
+      for (let i = 0; i < currentPlacements.length; ++i) {
+        if (currentPlacements[i] != defaultPlacements[i]) {
+          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 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);
+  },
+  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
+    );
+  },
+  getWidgetsInArea: 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).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;
+  }
+};
+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", "name", "description"];
+  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", "description"];
+  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);
+}
+
+// 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,241 @@
+/* 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";
+
+let gDebug = false;
+try {
+  gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
+} catch (e) {}
+
+function LOG(aMsg) {
+  if (gDebug) {
+    Services.console.logStringMessage("[CustomizableWidgets] " + aMsg);
+  }
+}
+function ERROR(aMsg) Cu.reportError("[CustomizableWidgets] " + aMsg);
+
+const CustomizableWidgets = [{
+    id: "history-panelmenu",
+    type: "view",
+    viewId: "PanelUI-history",
+    name: "History...",
+    description: "History",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL, CustomizableUI.AREA_NAVBAR],
+    icons: {
+      "16": "chrome://branding/content/icon16.png",
+      "32": "chrome://branding/content/icon48.png",
+      "48": "chrome://branding/content/icon48.png"
+    },
+    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);
+                  doc.defaultView.PanelUI.hide();
+                }
+              });
+              if (icon)
+                item.setAttribute("image", "moz-anno:favicon:" + icon);
+              fragment.appendChild(item);
+            } catch (e) {
+              Cu.reportError("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",
+    name: "Private Browsing\u2026",
+    description: "Open a new Private Browsing window",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    icons: {
+      "16": "chrome://branding/content/icon16.png",
+      "32": "chrome://branding/content/icon48.png",
+      "48": "chrome://branding/content/icon48.png"
+    },
+    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",
+    name: "Save Page",
+    shortcut: "Ctrl+S",
+    description: "Save this page",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    icons: {
+      "16": "chrome://branding/content/icon16.png",
+      "32": "chrome://branding/content/icon48.png",
+      "48": "chrome://branding/content/icon48.png"
+    },
+    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",
+    name: "Find",
+    shortcut: "Ctrl+F",
+    description: "Find in this page",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    icons: {
+      "16": "chrome://branding/content/icon16.png",
+      "32": "chrome://branding/content/icon48.png",
+      "48": "chrome://branding/content/icon48.png"
+    },
+    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",
+    name: "Open File",
+    shortcut: "Ctrl+O",
+    description: "Open file",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    icons: {
+      "16": "chrome://branding/content/icon16.png",
+      "32": "chrome://branding/content/icon48.png",
+      "48": "chrome://branding/content/icon48.png"
+    },
+    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",
+    name: "Developer",
+    shortcut: "Shift+F11",
+    description: "Toggle Developer Tools",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    icons: {
+      "16": "chrome://branding/content/icon16.png",
+      "32": "chrome://branding/content/icon48.png",
+      "48": "chrome://branding/content/icon48.png"
+    },
+    onCommand: function(aEvent) {
+      let win = aEvent.target &&
+                aEvent.target.ownerDocument &&
+                aEvent.target.ownerDocument.defaultView;
+      if (win && win.gDevToolsBrowser) {
+        win.gDevToolsBrowser.toggleToolboxCommand(win.gBrowser);
+      }
+    }
+  }, {
+    id: "add-ons-button",
+    name: "Add-ons",
+    shortcut: "Ctrl+Shift+A",
+    description: "Add-ons Manager",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    icons: {
+      "16": "chrome://branding/content/icon16.png",
+      "32": "chrome://branding/content/icon48.png",
+      "48": "chrome://branding/content/icon48.png"
+    },
+    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",
+    name: "Preferences",
+    shortcut: "Ctrl+Shift+O",
+    description: "Preferences\u2026",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    icons: {
+      "16": "chrome://branding/content/icon16.png",
+      "32": "chrome://branding/content/icon48.png",
+      "48": "chrome://branding/content/icon48.png"
+    },
+    onCommand: function(aEvent) {
+      let win = aEvent.target &&
+                aEvent.target.ownerDocument &&
+                aEvent.target.ownerDocument.defaultView;
+      if (win && typeof win.openPreferences == "function") {
+        win.openPreferences();
+      }
+    }
+  }];
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/src/CustomizeMode.jsm
@@ -0,0 +1,842 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["CustomizeMode"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+const kPrefCustomizationDebug = "browser.uiCustomization.debug";
+const kPaletteId = "customization-palette";
+const kAboutURI = "about:customizing";
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource:///modules/CustomizableUI.jsm");
+
+let gDebug = false;
+try {
+  gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
+} catch (e) {}
+
+function LOG(str) {
+  if (gDebug) {
+    Services.console.logStringMessage("[CustomizeMode] " + str);
+  }
+}
+
+function ERROR(aMsg) Cu.reportError("[CustomizeMode] " + aMsg);
+
+function CustomizeMode(aWindow) {
+  this.window = aWindow;
+  this.document = aWindow.document;
+  this.browser = aWindow.gBrowser;
+};
+
+CustomizeMode.prototype = {
+  _changed: false,
+  window: null,
+  document: null,
+  // areas is used to cache the customizable areas when in customization mode.
+  areas: null,
+  // When in customizing mode, we swap out the reference to the invisible
+  // palette in gNavToolbox.palette for our visiblePalette. This way, for the
+  // customizing browser window, when widgets are removed from customizable
+  // areas and added to the palette, they're added to the visible palette.
+  // _stowedPalette is a reference to the old invisible palette so we can
+  // restore gNavToolbox.palette to its original state after exiting
+  // customization mode.
+  _stowedPalette: null,
+  _dragOverItem: null,
+  _customizing: false,
+
+  get resetButton() {
+    return this.document.getElementById("customization-reset-button");
+  },
+
+  init: function() {
+    // There are two palettes - there's the palette that can be overlayed with
+    // toolbar items in browser.xul. This is invisible, and never seen by the
+    // user. Then there's the visible palette, which gets populated and displayed
+    // to the user when in customizing mode.
+    this.visiblePalette = this.document.getElementById(kPaletteId);
+
+    this.browser.tabContainer.addEventListener("TabSelect", this, false);
+    this.browser.addTabsProgressListener(this);
+  },
+
+  uninit: function() {
+    this.browser.tabContainer.removeEventListener("TabSelect", this, false);
+    this.browser.removeTabsProgressListener(this);
+  },
+
+  enter: function() {
+    if (this._customizing) {
+      return;
+    }
+
+    this.dispatchToolboxEvent("beforecustomization");
+
+    let window = this.window;
+    let document = this.document;
+
+    let customizer = document.getElementById("customization-container");
+    customizer.hidden = false;
+
+    // We don't need to switch to kAboutURI, or open a new tab at
+    // kAboutURI if we're already on it.
+    if (this.browser.selectedBrowser.currentURI.spec != kAboutURI) {
+      this.window.switchToTabHavingURI(kAboutURI, true);
+    }
+
+    CustomizableUI.addListener(this);
+
+    // The menu panel is lazy, and registers itself when the popup shows. We
+    // need to force the menu panel to register itself, or else customization
+    // is really not going to work.
+    window.PanelUI.ensureRegistered();
+
+    // Add a keypress listener and click listener to the tab-view-deck so that
+    // we can quickly exit customization mode when pressing ESC or clicking on
+    // the blueprint outside the customization container.
+    let deck = document.getElementById("tab-view-deck");
+    deck.addEventListener("keypress", this, false);
+    deck.addEventListener("click", this, false);
+
+    // Same goes for the menu button - if we're customizing, a click to the
+    // menu button means a quick exit from customization mode.
+    window.PanelUI.menuButton.addEventListener("click", this, false);
+    window.PanelUI.menuButton.disabled = true;
+
+    // Let everybody in this window know that we're about to customize.
+    this.dispatchToolboxEvent("customizationstarting");
+
+    customizer.parentNode.selectedPanel = customizer;
+
+    window.PanelUI.hide();
+    // Move the mainView in the panel to the holder so that we can see it
+    // while customizing.
+    let panelHolder = document.getElementById("customization-panelHolder");
+    panelHolder.appendChild(window.PanelUI.mainView);
+
+    let self = this;
+    deck.addEventListener("transitionend", function customizeTransitionEnd() {
+      deck.removeEventListener("transitionend", customizeTransitionEnd);
+
+      // Add drag-and-drop event handlers to all of the customizable areas.
+      self.areas = [];
+      for (let area of CustomizableUI.areas) {
+        let target = CustomizableUI.getCustomizeTargetForArea(area, window);
+        target.addEventListener("dragstart", self);
+        target.addEventListener("dragover", self);
+        target.addEventListener("dragexit", self);
+        target.addEventListener("drop", self);
+        target.addEventListener("dragend", self);
+        for (let child of target.children) {
+          if (self.isCustomizableItem(child)) {
+            self.wrapToolbarItem(child, getPlaceForItem(child));
+          }
+        }
+        self.areas.push(target);
+      }
+
+      self.populatePalette();
+      self.dispatchToolboxEvent("customizationready");
+    });
+
+    this.visiblePalette.addEventListener("dragstart", this);
+    this.visiblePalette.addEventListener("dragover", this);
+    this.visiblePalette.addEventListener("dragexit", this);
+    this.visiblePalette.addEventListener("drop", this);
+    this.visiblePalette.addEventListener("dragend", this);
+
+    this.resetButton.hidden = CustomizableUI.inDefaultState;
+
+    document.documentElement.setAttribute("customizing", true);
+    this._customizing = true;
+  },
+
+  exit: function() {
+    if (!this._customizing) {
+      return;
+    }
+
+    CustomizableUI.removeListener(this);
+
+    let deck = this.document.getElementById("tab-view-deck");
+    deck.removeEventListener("keypress", this, false);
+    deck.removeEventListener("click", this, false);
+    this.window.PanelUI.menuButton.removeEventListener("click", this, false);
+    this.window.PanelUI.menuButton.disabled = false;
+
+    this.depopulatePalette();
+
+    this.visiblePalette.removeEventListener("dragstart", this);
+    this.visiblePalette.removeEventListener("dragover", this);
+    this.visiblePalette.removeEventListener("dragexit", this);
+    this.visiblePalette.removeEventListener("drop", this);
+    this.visiblePalette.removeEventListener("dragend", this);
+
+    let window = this.window;
+    let document = this.document;
+
+    let documentElement = document.documentElement;
+    documentElement.setAttribute("customize-exiting", "true");
+    let tabViewDeck = document.getElementById("tab-view-deck");
+    tabViewDeck.addEventListener("transitionend", function onTransitionEnd(evt) {
+      if (evt.propertyName != "padding-top")
+        return;
+      tabViewDeck.removeEventListener("transitionend", onTransitionEnd);
+      documentElement.removeAttribute("customize-exiting");
+    });
+
+    for (let target of this.areas) {
+      for (let toolbarItem of target.children) {
+        if (this.isWrappedToolbarItem(toolbarItem)) {
+          this.unwrapToolbarItem(toolbarItem);
+        }
+      }
+      target.removeEventListener("dragstart", this);
+      target.removeEventListener("dragover", this);
+      target.removeEventListener("dragexit", this);
+      target.removeEventListener("drop", this);
+      target.removeEventListener("dragend", this);
+    }
+
+    if (this._changed) {
+      // XXXmconley: At first, it seems strange to also persist the old way with
+      //             currentset - but this might actually be useful for switching
+      //             to old builds. We might want to keep this around for a little
+      //             bit.
+      this.persistCurrentSets();
+    }
+
+    // And drop all area references.
+    this.areas = [];
+
+    // Let everybody in this window know that we're starting to
+    // exit customization mode.
+    this.dispatchToolboxEvent("customizationending");
+    window.PanelUI.replaceMainView(window.PanelUI.mainView);
+
+    let browser = document.getElementById("browser");
+    browser.parentNode.selectedPanel = browser;
+
+    // We need to set this._customizing to false before removing the tab
+    // or the TabSelect event handler will think that we are exiting
+    // customization mode for a second time.
+    this._customizing = false;
+
+    if (this.browser.selectedBrowser.currentURI.spec == kAboutURI) {
+      let custBrowser = this.browser.selectedBrowser;
+      if (custBrowser.canGoBack) {
+        // If there's history to this tab, just go back.
+        custBrowser.goBack();
+      } else {
+        // If we can't go back, we're removing the about:customization tab.
+        // We only do this if we're the top window for this window (so not
+        // a dialog window, for example).
+        if (this.window.getTopWin(true) == this.window) {
+          let customizationTab = this.browser.selectedTab;
+          if (this.browser.browsers.length == 1) {
+            this.window.BrowserOpenTab();
+          }
+          this.browser.removeTab(customizationTab);
+        }
+      }
+    }
+
+    let deck = document.getElementById("tab-view-deck");
+    let self = this;
+    deck.addEventListener("transitionend", function customizeTransitionEnd() {
+      deck.removeEventListener("transitionend", customizeTransitionEnd);
+      self.dispatchToolboxEvent("aftercustomization");
+    });
+    documentElement.removeAttribute("customizing");
+
+    let customizer = document.getElementById("customization-container");
+    customizer.hidden = true;
+
+    this._changed = false;
+  },
+
+  dispatchToolboxEvent: function(aEventType, aDetails={}) {
+    let evt = this.document.createEvent("CustomEvent");
+    evt.initCustomEvent(aEventType, true, true, {changed: this._changed});
+    let result = this.window.gNavToolbox.dispatchEvent(evt);
+  },
+
+  populatePalette: function() {
+    let toolboxPalette = this.window.gNavToolbox.palette;
+
+    let unusedWidgets = CustomizableUI.getUnusedWidgets(toolboxPalette);
+    for (let widget of unusedWidgets) {
+      let paletteItem = this.makePaletteItem(widget, "palette");
+      this.visiblePalette.appendChild(paletteItem);
+    }
+
+    this._stowedPalette = this.window.gNavToolbox.palette;
+    this.window.gNavToolbox.palette = this.visiblePalette;
+  },
+
+  //XXXunf Maybe this should use -moz-element instead of wrapping the node?
+  //       Would ensure no weird interactions/event handling from original node,
+  //       and makes it possible to put this in a lazy-loaded iframe/real tab
+  //       while still getting rid of the need for overlays.
+  makePaletteItem: function(aWidget, aPlace) {
+    let widgetNode = aWidget.forWindow(this.window).node;
+    let wrapper = this.createWrapper(widgetNode, aPlace);
+    wrapper.appendChild(widgetNode);
+    return wrapper;
+  },
+
+  depopulatePalette: function() {
+    let wrapper = this.visiblePalette.firstChild;
+
+    while (wrapper) {
+      let widgetNode = wrapper.firstChild;
+
+      let provider = CustomizableUI.getWidget(widgetNode.id);
+      // If provider is PROVIDER_SPECIAL, then it just gets thrown away.
+      if (provider = CustomizableUI.PROVIDER_XUL) {
+        if (wrapper.hasAttribute("itemdisabled")) {
+          widgetNode.disabled = true;
+        }
+
+        if (wrapper.hasAttribute("itemchecked")) {
+          widgetNode.checked = true;
+        }
+
+        if (wrapper.hasAttribute("itemcommand")) {
+          let commandID = wrapper.getAttribute("itemcommand");
+          widgetNode.setAttribute("command", commandID);
+
+          // Ensure node is in sync with its command after customizing.
+          let command = this.document.getElementById(commandID);
+          if (command && command.hasAttribute("disabled")) {
+            widgetNode.setAttribute("disabled",
+                                    command.getAttribute("disabled"));
+          }
+        }
+
+        this._stowedPalette.appendChild(widgetNode);
+      } else if (provider = CustomizableUI.PROVIDER_API) {
+        //XXXunf Currently this doesn't destroy the (now unused) node. It would
+        //       be good to do so, but we need to keep strong refs to it in
+        //       CustomizableUI (can't iterate of WeakMaps), and there's the
+        //       question of what behavior wrappers should have if consumers
+        //       keep hold of them.
+        //widget.destroyInstance(widgetNode);
+      }
+
+      this.visiblePalette.removeChild(wrapper);
+      wrapper = this.visiblePalette.firstChild;
+    }
+    this.window.gNavToolbox.palette = this._stowedPalette;
+  },
+
+  isCustomizableItem: function(aNode) {
+    return aNode.localName == "toolbarbutton" ||
+           aNode.localName == "toolbaritem" ||
+           aNode.localName == "toolbarseparator" ||
+           aNode.localName == "toolbarspring" ||
+           aNode.localName == "toolbarspacer";
+  },
+
+  isWrappedToolbarItem: function(aNode) {
+    return aNode.localName == "toolbarpaletteitem";
+  },
+
+  wrapToolbarItem: function(aNode, aPlace) {
+    let wrapper = this.createWrapper(aNode, aPlace);
+    // It's possible that this toolbar node is "mid-flight" and doesn't have
+    // a parent, in which case we skip replacing it. This can happen if a
+    // toolbar item has been dragged into the palette. In that case, we tell
+    // CustomizableUI to remove the widget from its area before putting the
+    // widget in the palette - so the node will have no parent.
+    if (aNode.parentNode) {
+      aNode = aNode.parentNode.replaceChild(wrapper, aNode);
+    }
+    wrapper.appendChild(aNode);
+    return wrapper;
+  },
+
+  createWrapper: function(aNode, aPlace) {
+    let wrapper = this.document.createElement("toolbarpaletteitem");
+
+    // "place" is used by toolkit to add the toolbarpaletteitem-palette
+    // binding to a toolbarpaletteitem, which gives it a label node for when
+    // it's sitting in the palette.
+    wrapper.setAttribute("place", aPlace);
+
+    // Ensure the wrapped item doesn't look like it's in any special state, and
+    // can't be interactved with when in the customization palette.
+    if (aNode.hasAttribute("command")) {
+      wrapper.setAttribute("itemcommand", aNode.getAttribute("command"));
+      aNode.removeAttribute("command");
+    }
+
+    if (aNode.checked) {
+      wrapper.setAttribute("itemchecked", "true");
+      aNode.checked = false;
+    }
+
+    if (aNode.disabled) {
+      wrapper.setAttribute("itemdisabled", "true");
+      aNode.disabled = false;
+    }
+
+    if (aNode.hasAttribute("id")) {
+      wrapper.setAttribute("id", "wrapper-" + aNode.getAttribute("id"));
+    }
+
+    if (aNode.hasAttribute("title")) {
+      wrapper.setAttribute("title", aNode.getAttribute("title"));
+    } else if (aNode.hasAttribute("label")) {
+      wrapper.setAttribute("title", aNode.getAttribute("label"));
+    }
+
+    if (aNode.hasAttribute("flex")) {
+      wrapper.setAttribute("flex", aNode.getAttribute("flex"));
+    }
+
+    wrapper.addEventListener("mousedown", this);
+    wrapper.addEventListener("mouseup", this);
+
+    return wrapper;
+  },
+
+  unwrapToolbarItem: function(aWrapper) {
+    aWrapper.removeEventListener("mousedown", this);
+    aWrapper.removeEventListener("mouseup", this);
+
+    let toolbarItem = aWrapper.firstChild;
+
+    if (aWrapper.hasAttribute("itemdisabled")) {
+      toolbarItem.disabled = true;
+    }
+
+    if (aWrapper.hasAttribute("itemchecked")) {
+      toolbarItem.checked = true;
+    }
+
+    if (aWrapper.hasAttribute("itemcommand")) {
+      let commandID = aWrapper.getAttribute("itemcommand");
+      toolbarItem.setAttribute("command", commandID);
+
+      //XXX Bug 309953 - toolbarbuttons aren't in sync with their commands after customizing
+      let command = this.document.getElementById(commandID);
+      if (command && command.hasAttribute("disabled")) {
+        toolbarItem.setAttribute("disabled", command.getAttribute("disabled"));
+      }
+    }
+
+    if (aWrapper.parentNode) {
+      aWrapper.parentNode.replaceChild(toolbarItem, aWrapper);
+    }
+    return toolbarItem;
+  },
+
+  persistCurrentSets: function()  {
+    let document = this.document;
+    let toolbars = document.querySelectorAll("toolbar[customizable='true']");
+    for (let toolbar of toolbars) {
+      let set = toolbar.currentSet;
+      toolbar.setAttribute("currentset", set);
+      LOG("Setting currentset of " + toolbar.id + " as " + set);
+      // Persist the currentset attribute directly on hardcoded toolbars.
+      document.persist(toolbar.id, "currentset");
+    }
+  },
+
+  reset: function() {
+    CustomizableUI.reset();
+  },
+
+  onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) {
+    this._onUIChange();
+  },
+
+  onWidgetAdded: function(aWidgetId, aArea, aPosition) {
+    this._onUIChange();
+  },
+
+  onWidgetRemoved: function(aWidgetId, aArea) {
+    this._onUIChange();
+  },
+
+  onWidgetCreated: function(aWidgetId) {
+  },
+
+  onWidgetDestroyed: function(aWidgetId) {
+  },
+
+  _onUIChange: function() {
+    this._changed = true;
+    this.resetButton.hidden = CustomizableUI.inDefaultState;
+    this.dispatchToolboxEvent("customizationchange");
+  },
+
+  handleEvent: function(aEvent) {
+    switch(aEvent.type) {
+      case "dragstart":
+        this._onDragStart(aEvent);
+        break;
+      case "dragover":
+        this._onDragOver(aEvent);
+        break;
+      case "drop":
+        this._onDragDrop(aEvent);
+        break;
+      case "dragexit":
+        this._onDragExit(aEvent);
+        break;
+      case "dragend":
+        this._onDragEnd(aEvent);
+        break;
+      case "mousedown":
+        this._onMouseDown(aEvent);
+        break;
+      case "mouseup":
+        this._onMouseUp(aEvent);
+        break;
+      case "keypress":
+        if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
+          this.exit();
+        }
+        break;
+      case "click":
+        if (aEvent.button == 0 &&
+            (aEvent.originalTarget == this.window.PanelUI.menuButton) ||
+            (aEvent.originalTarget == this.document.getElementById("tab-view-deck"))) {
+          this.exit();
+          aEvent.preventDefault();
+        }
+        break;
+      case "TabSelect":
+        this._onTabSelect(aEvent);
+        break;
+    }
+  },
+
+  _onDragStart: function(aEvent) {
+    __dumpDragData(aEvent);
+    let item = aEvent.target;
+    while (item && item.localName != "toolbarpaletteitem") {
+      if (item.localName == "toolbar") {
+        return;
+      }
+      item = item.parentNode;
+    }
+
+    let dt = aEvent.dataTransfer;
+    let documentId = aEvent.target.ownerDocument.documentElement.id;
+    dt.setData("text/toolbarwrapper-id/" + documentId, item.firstChild.id);
+    dt.effectAllowed = "move";
+  },
+
+  _onDragOver: function(aEvent) {
+    __dumpDragData(aEvent);
+
+    let document = aEvent.target.ownerDocument;
+    let documentId = document.documentElement.id;
+    if (!aEvent.dataTransfer.types.contains("text/toolbarwrapper-id/"
+                                            + documentId.toLowerCase())) {
+      return;
+    }
+
+    let draggedItemId = aEvent.dataTransfer.getData("text/toolbarwrapper-id/" + documentId);
+    let draggedWrapper = document.getElementById("wrapper-" + draggedItemId);
+    let targetNode = aEvent.target;
+    let targetParent = targetNode.parentNode;
+    let targetArea = this._getCustomizableParent(targetNode);
+    let originArea = this._getCustomizableParent(draggedWrapper);
+
+    // Do nothing if the target or origin are not customizable.
+    if (!targetArea || !originArea) {
+      return;
+    }
+
+    // Do nothing if thw widget is not allowed to be removed.
+    if (targetArea.id == kPaletteId &&
+       !CustomizableUI.isWidgetRemovable(draggedItemId)) {
+      return;
+    }
+
+    // Do nothing if the widget is not allowed to move to the target area.
+    if (targetArea.id != kPaletteId &&
+        !CustomizableUI.canWidgetMoveToArea(draggedItemId, targetArea.id)) {
+      return;
+    }
+
+    // We need to determine the place that the widget is being dropped in
+    // the target.
+    let position = Array.indexOf(targetParent.children, targetNode);
+    let dragOverItem = position == -1 ? targetParent.lastChild : targetParent.children[position];
+
+    if (this._dragOverItem && dragOverItem != this._dragOverItem) {
+      this._setDragActive(this._dragOverItem, false);
+    }
+
+    // XXXjaws Only handling the toolbar case first.
+    if (targetArea.localName == "toolbar") {
+      this._setDragActive(dragOverItem, true);
+    }
+    this._dragOverItem = dragOverItem;
+
+    aEvent.preventDefault();
+    aEvent.stopPropagation();
+  },
+
+  _onDragDrop: function(aEvent) {
+    __dumpDragData(aEvent);
+
+    this._setDragActive(this._dragOverItem, false);
+
+    let document = aEvent.target.ownerDocument;
+    let documentId = document.documentElement.id;
+    let draggedItemId = aEvent.dataTransfer.getData("text/toolbarwrapper-id/" + documentId);
+    let draggedWrapper = document.getElementById("wrapper-" + draggedItemId);
+
+    draggedWrapper.removeAttribute("mousedown");
+
+    let targetNode = aEvent.target;
+    let targetParent = targetNode.parentNode;
+    let targetArea = this._getCustomizableParent(targetNode);
+    let originArea = this._getCustomizableParent(draggedWrapper);
+
+    // Do nothing if the target area or origin area are not customizable.
+    if (!targetArea || !originArea) {
+      return;
+    }
+
+    // Do nothing if the target was dropped onto itself (ie, no change in area
+    // or position).
+    if (draggedWrapper == targetNode) {
+      return;
+    }
+
+    // Is the target area the customization palette? If so, we have two cases -
+    // either the originArea was the palette, or a customizable area.
+    if (targetArea.id == kPaletteId) {
+      if (originArea.id !== kPaletteId) {
+        if (!CustomizableUI.isWidgetRemovable(draggedItemId)) {
+          return;
+        }
+
+        let widget = this.unwrapToolbarItem(draggedWrapper);
+        CustomizableUI.removeWidgetFromArea(draggedItemId);
+        draggedWrapper = this.wrapToolbarItem(widget, "palette");
+      }
+
+      // If the targetNode is the palette itself, just append
+      if (targetNode == this.visiblePalette) {
+        this.visiblePalette.appendChild(draggedWrapper);
+      } else {
+        this.visiblePalette.insertBefore(draggedWrapper, targetNode);
+      }
+      return;
+    }
+
+    if (!CustomizableUI.canWidgetMoveToArea(draggedItemId, targetArea.id)) {
+      return;
+    }
+
+    // Is the target the customization area itself? If so, we just add the
+    // widget to the end of the area.
+    if (targetNode == targetArea.customizationTarget) {
+      let widget = this.unwrapToolbarItem(draggedWrapper);
+      CustomizableUI.addWidgetToArea(draggedItemId, targetArea.id);
+      this.wrapToolbarItem(widget, getPlaceForItem(targetNode));
+      return;
+    }
+
+    // We need to determine the place that the widget is being dropped in
+    // the target.
+    let placement = CustomizableUI.getPlacementOfWidget(targetNode.firstChild.id);
+    if (!placement) {
+      ERROR("Could not get a position for " + targetNode.firstChild.id);
+      return;
+    }
+
+    let position = placement.position;
+
+    // Is the target area the same as the origin? Since we've already handled
+    // the possibility that the target is the customization palette, we know
+    // that the widget is moving within a customizable area.
+    if (targetArea == originArea) {
+      let properPlace = getPlaceForItem(targetNode);
+      // We unwrap the moving widget, as well as the widget that we're dropping
+      // on (the target) so that moveWidgetWithinArea can correctly insert the
+      // moving widget before the target widget.
+      let widget = this.unwrapToolbarItem(draggedWrapper);
+      let targetWidget = this.unwrapToolbarItem(targetNode);
+      CustomizableUI.moveWidgetWithinArea(draggedItemId, position);
+      this.wrapToolbarItem(targetWidget, properPlace);
+      this.wrapToolbarItem(widget, properPlace);
+      return;
+    }
+
+    // A little hackery - we quickly unwrap the item and use CustomizableUI's
+    // addWidgetToArea to move the widget to the right place for every window,
+    // then we re-wrap the widget. We have to unwrap the target widget too so
+    // that addWidgetToArea inserts the new widget into the right place.
+    let properPlace = getPlaceForItem(targetNode);
+    let widget = this.unwrapToolbarItem(draggedWrapper);
+    let targetWidget = this.unwrapToolbarItem(targetNode);
+    CustomizableUI.addWidgetToArea(draggedItemId, targetArea.id, position);
+    this.wrapToolbarItem(targetWidget, properPlace);
+    draggedWrapper = this.wrapToolbarItem(widget, properPlace);
+  },
+
+  _onDragExit: function(aEvent) {
+    __dumpDragData(aEvent);
+    if (this._dragOverItem) {
+      this._setDragActive(this._dragOverItem, false);
+    }
+  },
+
+  _onDragEnd: function(aEvent) {
+    __dumpDragData(aEvent);
+    let document = aEvent.target.ownerDocument;
+    document.documentElement.removeAttribute("customizing-movingItem");
+
+    let documentId = document.documentElement.id;
+    if (!aEvent.dataTransfer.types.contains("text/toolbarwrapper-id/"
+                                            + documentId.toLowerCase())) {
+      return;
+    }
+
+    let draggedItemId = aEvent.dataTransfer.getData("text/toolbarwrapper-id/" + documentId);
+    let draggedWrapper = document.getElementById("wrapper-" + draggedItemId);
+
+    draggedWrapper.removeAttribute("mousedown");
+  },
+
+  // XXXjaws Show a ghost image or blank area where the item could be added, instead of black bar
+  _setDragActive: function(aItem, aValue) {
+    let node = aItem;
+    let window = aItem.ownerDocument.defaultView;
+    let direction = window.getComputedStyle(aItem, null).direction;
+    let value = direction == "ltr"? "left" : "right";
+    if (aItem.localName == "toolbar") {
+      node = aItem.lastChild;
+      value = direction == "ltr"? "right" : "left";
+    }
+
+    if (!node) {
+      return;
+    }
+
+    if (aValue) {
+      if (!node.hasAttribute("dragover")) {
+        node.setAttribute("dragover", value);
+      }
+    } else {
+      node.removeAttribute("dragover");
+    }
+  },
+
+  _getCustomizableParent: function(aElement) {
+    let areas = CustomizableUI.areas;
+    areas.push(kPaletteId);
+    while (aElement) {
+      if (areas.indexOf(aElement.id) != -1) {
+        return aElement;
+      }
+      aElement = aElement.parentNode;
+    }
+    return null;
+  },
+
+  _onMouseDown: function(aEvent) {
+    LOG("_onMouseDown");
+    let doc = aEvent.target.ownerDocument;
+    doc.documentElement.setAttribute("customizing-movingItem", true);
+    let item = this._getWrapper(aEvent.target);
+    if (item) {
+      item.setAttribute("mousedown", "true");
+    }
+  },
+
+  _onMouseUp: function(aEvent) {
+    LOG("_onMouseUp");
+    let doc = aEvent.target.ownerDocument;
+    doc.documentElement.removeAttribute("customizing-movingItem");
+    let item = this._getWrapper(aEvent.target);
+    if (item) {
+      item.removeAttribute("mousedown");
+    }
+  },
+
+  _getWrapper: function(aElement) {
+    while (aElement && aElement.localName != "toolbarpaletteitem") {
+      if (aElement.localName == "toolbar")
+        return null;
+      aElement = aElement.parentNode;
+    }
+    return aElement;
+  },
+
+  _onTabSelect: function(aEvent) {
+    this._toggleCustomizationModeIfNecessary();
+  },
+
+  onLocationChange: function(aBrowser, aProgress, aRequest, aLocation, aFlags) {
+    if (this.browser.selectedBrowser != aBrowser) {
+      return;
+    }
+
+    this._toggleCustomizationModeIfNecessary();
+  },
+
+  /**
+   * Looks at the currently selected browser tab, and if the location
+   * is set to kAboutURI and we're not customizing, enters customize mode.
+   * If we're not at kAboutURI and we are customizing, exits customize mode.
+   */
+  _toggleCustomizationModeIfNecessary: function() {
+    let browser = this.browser.selectedBrowser;
+    if (browser.currentURI.spec == kAboutURI &&
+        !this._customizing) {
+      this.enter();
+    } else if (browser.currentURI.spec != kAboutURI &&
+               this._customizing) {
+      this.exit();
+    }
+  }
+};
+
+function getPlaceForItem(aElement) {
+  let place;
+  let node = aElement;
+  while (node && !place) {
+    if (node.localName == "toolbar")
+      place = "toolbar";
+    else if (node.id == CustomizableUI.AREA_PANEL)
+      place = "panel";
+    else if (node.id == kPaletteId)
+      place = "palette";
+
+    node = node.parentNode;
+  }
+  return place;
+}
+
+function __dumpDragData(aEvent, caller) {
+  let str = "Dumping drag data (CustomizeMode.jsm) {\n";
+  str += "  type: " + aEvent["type"] + "\n";
+  for (let el of ["target", "currentTarget", "relatedTarget"]) {
+    if (aEvent[el]) {
+      str += "  " + el + ": " + aEvent[el] + "(localName=" + aEvent[el].localName + "; id=" + aEvent[el].id + ")\n";
+    }
+  }
+  for (let prop in aEvent.dataTransfer) {
+    if (typeof aEvent.dataTransfer[prop] != "function") {
+      str += "  dataTransfer[" + prop + "]: " + aEvent.dataTransfer[prop] + "\n";
+    }
+  }
+  str += "}";
+  LOG(str);
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/src/Makefile.in
@@ -0,0 +1,18 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH     = @DEPTH@
+topsrcdir = @top_srcdir@
+srcdir    = @srcdir@
+VPATH     = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+EXTRA_JS_MODULES = \
+  CustomizableUI.jsm \
+  CustomizableWidgets.jsm \
+  CustomizeMode.jsm \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/src/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/.
+
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -2,16 +2,17 @@
 # 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 += [
     'about',
     'certerror',
+    'customizableui',
     'dirprovider',
     'downloads',
     'feeds',
     'places',
     'preferences',
     'privatebrowsing',
     'search',
     'sessionstore',
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1166,17 +1166,17 @@ BrowserGlue.prototype = {
     var notifyBox = win.gBrowser.getNotificationBox();
     var notification = notifyBox.appendNotification(text, title, null,
                                                     notifyBox.PRIORITY_CRITICAL_MEDIUM,
                                                     buttons);
     notification.persistence = -1; // Until user closes it
   },
 
   _migrateUI: function BG__migrateUI() {
-    const UI_VERSION = 13;
+    const UI_VERSION = 14;
     const BROWSER_DOCURL = "chrome://browser/content/browser.xul#";
     let currentUIVersion = 0;
     try {
       currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
     } catch(ex) {}
     if (currentUIVersion >= UI_VERSION)
       return;
 
@@ -1356,16 +1356,44 @@ BrowserGlue.prototype = {
     if (currentUIVersion < 13) {
       try {
         if (Services.prefs.getBoolPref("plugins.hide_infobar_for_missing_plugin"))
           Services.prefs.setBoolPref("plugins.notifyMissingFlash", false);
       }
       catch (ex) {}
     }
 
+    if (currentUIVersion < 13) {
+      // Migrate users from text or text&icons mode to icons mode.
+      let toolbarResources = [this._rdf.GetResource(BROWSER_DOCURL + "navigator-toolbox"),
+                              this._rdf.GetResource(BROWSER_DOCURL + "nav-bar"),
+                              this._rdf.GetResource(BROWSER_DOCURL + "PersonalToolbar"),
+                              this._rdf.GetResource(BROWSER_DOCURL + "addon-bar")];
+      let modeResource = this._rdf.GetResource("mode");
+      let iconsizeResource = this._rdf.GetResource("iconsize");
+      for (let toolbarResource of toolbarResources) {
+        let toolbarMode = this._getPersist(toolbarResource, modeResource);
+        if (toolbarMode != "icons") {
+          this._setPersist(toolbarResource, modeResource, "icons");
+          // If the user wasn't previously using icons mode, switch
+          // them to the default (large icon mode).
+          this._setPersist(toolbarResource, iconsizeResource, "large");
+        }
+      }
+    }
+
+    if (currentUIVersion < 14) {
+      let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar");
+      let collapsedResource = this._rdf.GetResource("collapsed");
+      let isCollapsed = this._getPersist(toolbarResource, collapsedResource);
+      if (isCollapsed == "true") {
+        this._setPersist(toolbarResource, collapsedResource, "false");
+      }
+    }
+
     if (this._dirty)
       this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
 
     delete this._rdf;
     delete this._dataSource;
 
     // Update the migration version.
     Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
--- a/browser/components/tabview/test/browser_tabview_bug626791.js
+++ b/browser/components/tabview/test/browser_tabview_bug626791.js
@@ -1,11 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+Cu.import("resource:///modules/CustomizableUI.jsm");
+
+
 function test() {
   let cw;
   let win;
   let prefix;
 
   let getToolbar = function () {
     return win.document.getElementById("TabsToolbar");
   }
@@ -26,20 +29,17 @@ function test() {
 
   let removeToolbarButton = function () {
     let toolbar = getToolbar();
     let currentSet = toolbar.currentSet.split(",");
     let buttonId = "tabview-button";
     let pos = currentSet.indexOf(buttonId);
 
     if (-1 < pos) {
-      currentSet.splice(pos, 1);
-      toolbar.setAttribute("currentset", currentSet.join(","));
-      toolbar.currentSet = currentSet.join(",");
-      win.document.persist(toolbar.id, "currentset");
+      CustomizableUI.removeWidgetFromArea("tabview-button");
     }
   }
 
   let testNameGroup = function () {
     prefix = 'name-group';
     assertToolbarButtonNotExists();
     let groupItem = cw.GroupItems.groupItems[0];
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -10,16 +10,18 @@
 <!-- LOCALIZATION NOTE (mainWindow.titlemodifier) : DONT_TRANSLATE -->
 <!ENTITY mainWindow.titlemodifier "&brandFullName;">
 <!-- LOCALIZATION NOTE (mainWindow.titlemodifiermenuseparator): DONT_TRANSLATE -->
 <!ENTITY mainWindow.titlemodifiermenuseparator " - ">
 <!-- LOCALIZATION NOTE (mainWindow.titlePrivateBrowsingSuffix): This will be appended to the window's title
                                                                 inside the private browsing mode -->
 <!ENTITY mainWindow.titlePrivateBrowsingSuffix "(Private Browsing)">
 
+<!ENTITY appmenu.title                       "Customize and Control &brandFullName;">
+
 <!-- Tab context menu -->
 <!ENTITY  reloadTab.label                    "Reload Tab">
 <!ENTITY  reloadTab.accesskey                "R">
 <!ENTITY  reloadAllTabs.label                "Reload All Tabs">
 <!ENTITY  reloadAllTabs.accesskey            "A">
 <!ENTITY  closeOtherTabs.label               "Close Other Tabs">
 <!ENTITY  closeOtherTabs.accesskey           "o">
 
@@ -63,17 +65,16 @@ can reach it easily. -->
 <!ENTITY printCmd.commandkey "p">
 
 <!ENTITY goOfflineCmd.label "Work Offline">
 <!ENTITY goOfflineCmd.accesskey "k">
 
 <!ENTITY menubarCmd.label "Menu Bar">
 <!ENTITY menubarCmd.accesskey "M">
 <!ENTITY navbarCmd.label "Navigation Toolbar">
-<!ENTITY navbarCmd.accesskey "N">
 <!ENTITY personalbarCmd.label "Bookmarks Toolbar">
 <!ENTITY personalbarCmd.accesskey "B">
 <!ENTITY bookmarksToolbarItem.label "Bookmarks Toolbar Items">
 <!ENTITY addonBarCmd.label "Add-on Bar">
 <!ENTITY addonBarCmd.accesskey "A">
 
 <!ENTITY pageSourceCmd.label "Page Source">
 <!ENTITY pageSourceCmd.accesskey "o">
@@ -155,18 +156,16 @@ These should match what Safari and other
 
 <!ENTITY backForwardItem.title        "Back/Forward">
 <!ENTITY locationItem.title           "Location">
 <!ENTITY searchItem.title             "Search">
 <!ENTITY throbberItem.title           "Activity Indicator">
 <!ENTITY bookmarksItem.title          "Bookmarks">
 
 <!-- Toolbar items --> 
-<!ENTITY appMenuButton.label          "Menu">
-<!ENTITY appMenuButton.tooltip        "Open &brandShortName; menu">
 <!ENTITY homeButton.label             "Home">
 
 <!ENTITY tabGroupsButton.label        "Tab Groups">
 <!ENTITY tabGroupsButton.tooltip      "Group your tabs">
 
 <!ENTITY feedButton.label             "Subscribe">
 <!ENTITY feedButton.tooltip           "Subscribe to this page…">
 
@@ -315,26 +314,22 @@ These should match what Safari and other
 <!-- LOCALIZATION NOTE (historyUndoWindowMenu): see bug 394759 -->
 <!ENTITY historyUndoWindowMenu.label "Recently Closed Windows">
 <!ENTITY historyRestoreLastSession.label "Restore Previous Session">
 
 <!ENTITY historyHomeCmd.label "Home">
 <!ENTITY showAllHistoryCmd2.label "Show All History">
 <!ENTITY showAllHistoryCmd.commandkey "H">
 
-<!ENTITY appMenuEdit.label "Edit">
 <!ENTITY appMenuCustomize.label "Customize">
-<!ENTITY appMenuToolbarLayout.label "Toolbar Layout…">
-<!ENTITY appMenuSidebars.label "Sidebars">
-<!ENTITY appMenuFind.label "Find…">
-<!ENTITY appMenuUnsorted.label "Unsorted Bookmarks">
-<!ENTITY appMenuWebDeveloper.label "Web Developer">
-<!ENTITY appMenuGettingStarted.label "Getting Started">
-<!ENTITY appMenuSafeMode.label "Restart with Add-ons Disabled…">
-<!ENTITY appMenuSafeMode.accesskey "R">
+<!ENTITY appMenuBookmarks.label "Bookmarks">
+<!ENTITY appMenuHistory.label "History">
+<!ENTITY appMenuHistory.showAll.label "Show All History">
+<!ENTITY appMenuHistory.clearRecent.label "Clear Recent History…">
+<!ENTITY appMenuHistory.restoreSession.label "Restore Previous Session">
 
 <!ENTITY openCmd.commandkey           "l">
 <!ENTITY urlbar.placeholder2          "Search or enter address">
 <!ENTITY urlbar.accesskey             "d">
 <!ENTITY urlbar.switchToTab.label     "Switch to tab:">
 
 <!-- 
   Comment duplicated from browser-sets.inc:
@@ -536,16 +531,17 @@ you can use these alternative items. Oth
 <!ENTITY copyButton.tooltip             "Copy">
 <!ENTITY pasteButton.tooltip            "Paste">
 
 <!ENTITY fullScreenButton.tooltip       "Display the window in full screen">
 
 <!ENTITY zoomOutButton.tooltip          "Zoom out">
 <!ENTITY zoomInButton.tooltip           "Zoom in">
 <!ENTITY zoomControls.label             "Zoom Controls">
+<!ENTITY zoomReset.tooltip              "Reset Zoom">
 
 <!ENTITY quitApplicationCmdWin.label       "Exit"> 
 <!ENTITY quitApplicationCmdWin.accesskey   "x">
 <!ENTITY goBackCmd.commandKey "[">
 <!ENTITY goForwardCmd.commandKey "]">
 <!ENTITY quitApplicationCmd.label       "Quit"> 
 <!ENTITY quitApplicationCmd.accesskey   "Q">
 <!ENTITY quitApplicationCmdMac.label    "Quit &brandShortName;">
@@ -646,16 +642,23 @@ just addresses the organization to follo
 
 <!ENTITY social.activated.description "Services from <label/> have been enabled. You can change your settings for services in the <label class='text-link'>Add-on Manager</label>.">
 <!ENTITY social.activated.undo.label "Oops, undo this!">
 <!ENTITY social.activated.undo.accesskey "U">
 <!ENTITY social.learnMore.label "Learn more…">
 <!ENTITY social.learnMore.accesskey "l">
 <!ENTITY social.closeNotificationItem.label "Not Now">
 
+
+
+<!ENTITY customizeMode.tabTitle "Customize &brandShortName;">
+<!ENTITY customizeMode.menuAndToolbars.label "Menu and toolbars">
+<!ENTITY customizeMode.menuAndToolbars.header "More Tools to Add to the Menu and Toolbar">
+<!ENTITY customizeMode.restoreDefaults "Restore Defaults">
+
 <!ENTITY social.chatBar.commandkey "c">
 <!ENTITY social.chatBar.label "Focus chats">
 <!ENTITY social.chatBar.accesskey "c">
 
 <!-- labels are set dynamically, see browser.properties -->
 <!ENTITY social.markpage.accesskey "m">
 <!ENTITY social.marklink.accesskey "M">
 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -460,8 +460,11 @@ mixedContentBlocked.unblock.label = Disa
 mixedContentBlocked.unblock.accesskey = D
 
 # LOCALIZATION NOTE - %S is brandShortName
 slowStartup.message = %S seems slow… to… start.
 slowStartup.helpButton.label = Learn How to Speed It Up
 slowStartup.helpButton.accesskey = L
 slowStartup.disableNotificationButton.label = Don't Tell Me Again
 slowStartup.disableNotificationButton.accesskey = A
+
+# LOCALIZATION NOTE(zoomReset.label): %S is the current zoom level.
+zoomReset.label = %S%%
--- a/browser/modules/webappsUI.jsm
+++ b/browser/modules/webappsUI.jsm
@@ -42,55 +42,16 @@ this.webappsUI = {
         WebappOSUtils.launch(data);
         break;
       case "webapps-uninstall":
         WebappOSUtils.uninstall(data);
         break;
     }
   },
 
-  openURL: function(aUrl, aOrigin) {
-    let browserEnumerator = Services.wm.getEnumerator("navigator:browser");
-    let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-
-    // Check each browser instance for our URL
-    let found = false;
-    while (!found && browserEnumerator.hasMoreElements()) {
-      let browserWin = browserEnumerator.getNext();
-      let tabbrowser = browserWin.gBrowser;
-
-      // Check each tab of this browser instance
-      let numTabs = tabbrowser.tabs.length;
-      for (let index = 0; index < numTabs; index++) {
-        let tab = tabbrowser.tabs[index];
-        let appURL = ss.getTabValue(tab, "appOrigin");
-        if (appURL == aOrigin) {
-          // The URL is already opened. Select this tab.
-          tabbrowser.selectedTab = tab;
-          browserWin.focus();
-          found = true;
-          break;
-        }
-      }
-    }
-
-    // Our URL isn't open. Open it now.
-    if (!found) {
-      let recentWindow = Services.wm.getMostRecentWindow("navigator:browser");
-      if (recentWindow) {
-        // Use an existing browser window
-        let browser = recentWindow.gBrowser;
-        let tab = browser.addTab(aUrl);
-        browser.pinTab(tab);
-        browser.selectedTab = tab;
-        ss.setTabValue(tab, "appOrigin", aOrigin);
-      }
-    }
-  },
-
   _getBrowserForId: function(aId) {
     let content = Services.wm.getOuterWindowWithId(aId);
     if (content) {
       let browser = content.QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIWebNavigation)
                     .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
       let win = browser.ownerDocument.defaultView;
       return [win, browser];
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4d0f12492fe643ade04a8ffaf333f7c729fa2f33
GIT binary patch
literal 247
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%``#fD7Ln>~ay|9<>AcIKT!^dVh
zPL~`nny9FX3QF0_hAc6;6tcysgRf4^t^C677rbS5HPZ`DB~%<wuk4)Jec#12dB&70
zX5l8mB0M@P+otl$&VQS#!NoRhkAa_i-U;LXK(-kF7yrj|Uf%a#Q@&=&9fQb=)r%4m
zJYV}6S8siM^qCG&@t?z{rA;&T{*4vkc_Z(0<&5Vdlix9>I)Mfou1K9RHs4iHP}kMe
uxHR{V$Mxmx?%StpNZgq3<I+0kqV!JNQte+wg;Rk(VeoYIb6Mw<&;$VPyJO}6
new file mode 100644
--- /dev/null
+++ b/browser/themes/linux/browser-lightweightTheme.css
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+%include linuxShared.inc
+%filter substitution
+
+/*
+ * LightweightThemeListener will append the current lightweight theme's header
+ * image to the background-image for each of the following rulesets.
+ */
+
+/* Lightweight theme on tabs */
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
+  background-attachment: scroll, fixed;
+  background-color: transparent;
+  background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
+  background-position: 0 0, right top;
+}
+
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
+  background-attachment: scroll, scroll, fixed;
+  background-color: transparent;
+  background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
+                    @fgTabTextureLWT@;/*,
+                    lwtHeader;*/
+  background-position: 0 0, 0 0, right top;
+}
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -5,22 +5,22 @@
 %endif
 
 @import url("chrome://global/skin/");
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 @namespace html url("http://www.w3.org/1999/xhtml");
 
 %include ../shared/browser.inc
+%include linuxShared.inc
 %filter substitution
-%define toolbarHighlight rgba(255,255,255,.3)
-%define selectedTabHighlight rgba(255,255,255,.8) 1px, rgba(255,255,255,.5) 3px
+
 %define forwardTransitionLength 150ms
-%define conditionalForwardWithUrlbar       window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"][mode=icons],                #nav-bar:not([currentset])[mode=icons])                 > #unified-back-forward-button
-%define conditionalForwardWithUrlbar_small window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"][mode=icons][iconsize=small],#nav-bar:not([currentset])[mode=icons][iconsize=small]) > #unified-back-forward-button
+%define conditionalForwardWithUrlbar       window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"],                #nav-bar:not([currentset]))                 > #nav-bar-customizationtarget > #unified-back-forward-button
+%define conditionalForwardWithUrlbar_small window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"][iconsize=small],#nav-bar:not([currentset])[iconsize=small]) > #nav-bar-customizationtarget > #unified-back-forward-button
 %define conditionalForwardWithUrlbarWidth 32
 %define conditionalForwardWithUrlbarWidth_small 24
 
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
 #main-menubar {
@@ -28,17 +28,17 @@
 }
 
 #navigator-toolbox {
   -moz-appearance: none;
   background-color: transparent;
   border-top: none;
 }
 
-#main-window:not([disablechrome]) #navigator-toolbox[tabsontop=true] {
+#navigator-toolbox[tabsontop=true] {
   border-bottom: 1px solid ThreeDShadow;
 }
 
 #navigator-toolbox[tabsontop=true] > toolbar:not(:-moz-lwtheme):not(#toolbar-menubar):not(#TabsToolbar),
 #navigator-toolbox[tabsontop=false] > toolbar:not(:-moz-lwtheme):not(#toolbar-menubar) {
   -moz-appearance: none;
   border-style: none;
   background-color: -moz-Dialog;
@@ -48,21 +48,31 @@
   padding-top: 1px;
   padding-bottom: 1px;
 }
 
 #nav-bar:not(:-moz-lwtheme),
 #nav-bar[collapsed=true] + toolbar:not(:-moz-lwtheme),
 #nav-bar[collapsed=true] + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme),
 #nav-bar[tabsontop=true],
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar,
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar {
+#nav-bar[tabsontop=true][collapsed=true] + toolbar,
+#nav-bar[tabsontop=true][collapsed=true] + #customToolbars + #PersonalToolbar {
   background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
 }
 
+#nav-bar[tabsontop=true],
+#nav-bar[tabsontop=true][collapsed=true] + toolbar,
+#nav-bar[tabsontop=true][collapsed=true] + #customToolbars + #PersonalToolbar {
+  box-shadow: 0 1px 0 @toolbarHighlight@ inset;
+  margin-top: -1px; /* Move up 1px into the TabsToolbar */
+  /* Position the toolbar above the bottom of background tabs */
+  position: relative;
+  z-index: 1;
+}
+
 #personal-bookmarks {
   min-height: 29px;
 }
 
 #browser-bottombox {
   /* opaque for layers optimization */
   background-color: -moz-Dialog;
 }
@@ -91,17 +101,17 @@ toolbarbutton.bookmark-item[open="true"]
   height: 16px;
 }
 
 #PlacesToolbarItems > .bookmark-item:not([image]):not([label=""]):not([container]) > .toolbarbutton-icon {
   display: none;
 }
 
 
-/* Prevent [mode="icons"] from hiding the label */
+/* Force the display of the label for bookmarks */
 .bookmark-item > .toolbarbutton-text {
   display: -moz-box !important;
 }
 
 .bookmark-item > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
@@ -213,77 +223,68 @@ menuitem.bookmark-item {
   opacity: 0.7;
 }
 
 /* Stock icons for the menu bar items */
 menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic");
 }
 
-#appmenu_newNavigator,
 #placesContext_open\:newwindow,
 #menu_newNavigator,
 #context-openlink,
 #context-openframe {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 80px 16px 64px);
 }
 
-#appmenu_newTab,
-#appmenu_newTab_popup,
 #placesContext_open\:newtab,
 #placesContext_openContainer\:tabs,
 #menu_newNavigatorTab,
 #context-openlinkintab,
 #context-openframeintab {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 64px 16px 48px);
 }
 
-#appmenu_openFile,
 #menu_openFile {
   list-style-image: url("moz-icon://stock/gtk-open?size=menu");
 }
 
 #menu_close {
   list-style-image: url("moz-icon://stock/gtk-close?size=menu");
 }
 
 #context-media-play {
   list-style-image: url("moz-icon://stock/gtk-media-play?size=menu");
 }
 
 #context-media-pause {
   list-style-image: url("moz-icon://stock/gtk-media-pause?size=menu");
 }
 
-#appmenu_savePage,
 #menu_savePage,
 #context-savelink,
 #context-saveimage,
 #context-savevideo,
 #context-saveaudio,
 #context-savepage,
 #context-saveframe {
   list-style-image: url("moz-icon://stock/gtk-save-as?size=menu");
 }
 
-#appmenu_printPreview,
 #menu_printPreview {
   list-style-image: url("moz-icon://stock/gtk-print-preview?size=menu");
 }
 
-#appmenu_print,
-#appmenu_print_popup,
 #menu_print,
 #context-printframe {
   list-style-image: url("moz-icon://stock/gtk-print?size=menu");
 }
 
-#appmenu-quit,
 #menu_FileQuitItem {
   list-style-image: url("moz-icon://stock/gtk-quit?size=menu");
 }
 
 #menu_undo,
 #context-undo {
   list-style-image: url("moz-icon://stock/gtk-undo?size=menu");
 }
@@ -356,27 +357,24 @@ menuitem:not([type]):not(.menuitem-toolt
   list-style-image: url("moz-icon://stock/gtk-delete?size=menu&state=disabled");
 }
 
 #menu_selectAll,
 #context-selectall {
   list-style-image: url("moz-icon://stock/gtk-select-all?size=menu");
 }
 
-#appmenu_find,
 #menu_find {
   list-style-image: url("moz-icon://stock/gtk-find?size=menu");
 }
 
 #menu_find[disabled] {
   list-style-image: url("moz-icon://stock/gtk-find?size=menu&state=disabled");
 }
 
-#appmenu_customize,
-#appmenu_preferences,
 #menu_preferences {
   list-style-image: url("moz-icon://stock/gtk-preferences?size=menu");
 }
 
 #menu_stop,
 #context-stop {
   list-style-image: url("moz-icon://stock/gtk-stop?size=menu");
 }
@@ -449,25 +447,21 @@ menuitem:not([type]):not(.menuitem-toolt
 #context-forward[disabled]:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled");
 }
 
 #historyMenuHome {
   list-style-image: url("moz-icon://stock/gtk-home?size=menu");
 }
 
-#appmenu_history,
-#appmenu_showAllHistory,
 #menu_showAllHistory {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 32px 16px 16px);
 }
 
-#appmenu_bookmarks,
-#appmenu_showAllBookmarks,
 #bookmarksShowAll {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 48px 16px 32px);
 }
 
 #subscribeToPageMenuitem:not([disabled]),
 #subscribeToPageMenupopup,
 #BMB_subscribeToPageMenuitem:not([disabled]),
@@ -483,55 +477,47 @@ menuitem:not([type]):not(.menuitem-toolt
 #BMB_bookmarkThisPage {
   list-style-image: url("chrome://browser/skin/places/starPage.png");
 }
 
 #BMB_unsortedBookmarks {
   list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
 }
 
-#appmenu_downloads,
 #menu_openDownloads {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 16px 16px 0px);
 }
 
-#appmenu_addons,
 #menu_openAddons {
   list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png");
 }
 
 #menu_pageInfo,
 #context-viewinfo,
 #context-viewframeinfo {
   list-style-image: url("moz-icon://stock/gtk-info?size=menu");
 }
 
-#appmenu_privateBrowsing,
-#appmenu_newPrivateWindow,
 #privateBrowsingItem {
   list-style-image: url("chrome://browser/skin/Privacy-16.png");
 }
 
 #placesContext_show\:info {
   list-style-image: url("moz-icon://stock/gtk-properties?size=menu");
 }
 
-#appmenu_sanitizeHistory,
 #sanitizeItem {
   list-style-image: url("moz-icon://stock/gtk-clear?size=menu");
 }
 
-#appmenu_help,
-#appmenu_openHelp,
 #menu_openHelp {
   list-style-image: url("moz-icon://stock/gtk-help?size=menu");
 }
 
-#appmenu_about,
 #aboutName {
   list-style-image: url("moz-icon://stock/gtk-about?size=menu");
 }
 
 #javascriptConsole {
   list-style-image: url("chrome://global/skin/console/console.png");
 }
 
@@ -541,21 +527,16 @@ menuitem:not([type]):not(.menuitem-toolt
   min-width: 0;
   list-style-image: url("chrome://browser/skin/Toolbar.png");
 }
 
 .toolbarbutton-1 > .toolbarbutton-icon {
   -moz-margin-end: 0;
 }
 
-toolbar[mode="full"] .toolbarbutton-1:not([type="menu-button"]),
-toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
-  min-width: 57px;
-}
-
 .toolbarbutton-1:not([type="menu-button"]),
 .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   padding: 5px;
 }
 
 .toolbarbutton-1[checked="true"] {
   padding: 5px !important;
 }
@@ -649,17 +630,19 @@ toolbar[mode="full"] .toolbarbutton-1 > 
 #menu_tabview[groups="3"] {
   -moz-image-region: rect(0, 64px, 16px, 48px);
 }
 
 #downloads-button {
   -moz-image-region: rect(0px 24px 24px 0px);
 }
 
-#history-button {
+#history-button,
+toolbar > .customization-target > #history-panelmenu,
+toolbar > .customization-target > toolbarpaletteitem > #history-panelmenu {
   -moz-image-region: rect(0px 48px 24px 24px);
 }
 
 #bookmarks-button,
 #bookmarks-menu-button {
   -moz-image-region: rect(0px 72px 24px 48px);
 }
 
@@ -681,49 +664,63 @@ toolbar[mode="full"] .toolbarbutton-1 > 
 #new-tab-button {
   -moz-image-region: rect(0px 96px 24px 72px);
 }
 
 #new-window-button {
   -moz-image-region: rect(0px 120px 24px 96px);
 }
 
+/* A lot of these buttons are going to be removed in later bugs, but until then
+ * we're overriding the menuPanel-icons sprites with these ones with
+ * !important.
+ *
+ * Here are the relevant removal bugs:
+ * #bookmarks-button - Bug 867368
+ * #cut-button, #copy-button, #paste-button - Bug 870901
+ * #zoom-out-button, #zoom-in-button - Bug 870897
+ */
+
+#bookmarks-button {
+  list-style-image: url("chrome://browser/skin/Toolbar.png") !important;
+}
+
 #cut-button {
-  list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar");
+  list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar") !important;
 }
 #cut-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar&state=disabled");
+  list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar&state=disabled") !important;
 }
 
 #copy-button {
-  list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar");
+  list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar") !important;
 }
 #copy-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar&state=disabled");
+  list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar&state=disabled") !important;
 }
 
 #paste-button {
-  list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar");
+  list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar") !important;
 }
 #paste-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar&state=disabled");
+  list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar&state=disabled") !important;
+}
+
+#zoom-out-button {
+  list-style-image: url("moz-icon://stock/gtk-zoom-out?size=toolbar") !important;
+}
+
+#zoom-in-button {
+  list-style-image: url("moz-icon://stock/gtk-zoom-in?size=toolbar") !important;
 }
 
 #fullscreen-button {
   list-style-image: url("moz-icon://stock/gtk-fullscreen?size=toolbar");
 }
 
-#zoom-out-button {
-  list-style-image: url("moz-icon://stock/gtk-zoom-out?size=toolbar");
-}
-
-#zoom-in-button {
-  list-style-image: url("moz-icon://stock/gtk-zoom-in?size=toolbar");
-}
-
 #sync-button {
   -moz-image-region: rect(0px 144px 24px 120px);
 }
 #sync-button[status="active"] {
   list-style-image: url("chrome://browser/skin/sync-24-throbber.png");
   -moz-image-region: rect(0px 24px 24px 0px);
 }
 
@@ -1611,135 +1608,73 @@ richlistitem[type~="action"][actiontype=
 
 #navigator-throbber,
 #wrapper-navigator-throbber > #navigator-throbber {
   list-style-image: url("chrome://global/skin/icons/notloading_16.png");
 }
 
 /* Tabstrip */
 
+%include ../shared/tabs.inc.css
+
+#tabbrowser-tabs {
+  /* override the global style to allow the selected tab to be above the nav-bar */
+  z-index: auto;
+}
+
 #TabsToolbar {
   min-height: 0;
   padding: 0;
+  position: relative;
+}
+
+/*
+ * Draw the bottom border of the tabstrip:
+ */
+#TabsToolbar::after {
+  content: "";
+  position: absolute;
+  bottom: 1px;
+  left: 0;
+  right: 0;
+  z-index: 0;
+  border-bottom: 1px solid hsla(0,0%,0%,.3);
 }
 
 #TabsToolbar[tabsontop=true]:not(:-moz-lwtheme) {
   -moz-appearance: menubar;
   color: -moz-menubartext;
-  box-shadow: 0 -1px 0 rgba(0,0,0,.1) inset;
-}
-
+}
+
+#toolbar-menubar:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
 #TabsToolbar[tabsontop=true]:not(:-moz-lwtheme):-moz-system-metric(menubar-drag) {
-  -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-drag");
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
+}
+
+#TabsToolbar[tabsontop=true]:not(:-moz-lwtheme) > #tabbrowser-tabs > .tabbrowser-tab:not([selected]) {
+  color: -moz-menubartext;
 }
 
 #TabsToolbar[tabsontop=false] {
   background-image: linear-gradient(to top, rgba(0,0,0,.3) 1px, rgba(0,0,0,.05) 1px, transparent 50%);
 }
 
-.tabbrowser-tab,
-.tabs-newtab-button {
-  position: static;
-  -moz-appearance: none;
-  background: linear-gradient(hsla(0,0%,100%,.2), hsla(0,0%,45%,.2) 2px, hsla(0,0%,32%,.2) 80%);
-  background-origin: border-box;
-  background-position: 1px 2px;
-  background-size: 100% calc(100% - 2px);
-  background-repeat: no-repeat;
-  color: inherit;
-  margin: 0;
-  padding: 0;
-  border-width: 4px 5px 3px 6px;
-  border-style: solid;
-  border-image: url(tabbrowser/tab.png) 4 5 3 6 fill repeat stretch;
-  border-radius: 10px 8px 0 0;
-  min-height: 25px; /* reserve space for the sometimes hidden close button */
-}
-
-.tabbrowser-tab:hover,
-.tabs-newtab-button:hover {
-  background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.2) 4px, hsla(0,0%,75%,.2) 80%);
-}
-
-.tabbrowser-tab[selected="true"] {
-  background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%),
-                    linear-gradient(-moz-dialog, -moz-dialog);
-  color: -moz-dialogtext;
-}
-
-#main-window[tabsontop=false]:not([disablechrome]) .tabbrowser-tab[selected=true]:not(:-moz-lwtheme) {
-  background-image: linear-gradient(to top, rgba(0,0,0,.3) 1px, transparent 1px),
-                    linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%),
-                    linear-gradient(-moz-dialog, -moz-dialog);
-}
-
-.tabbrowser-tab[selected="true"]:-moz-lwtheme {
-  background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%);
+.tab-background-middle[selected=true]:-moz-lwtheme {
+  background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
+                    @fgTabTexture@;
+}
+
+.tabbrowser-tab:-moz-lwtheme {
   color: inherit;
 }
 
-.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]),
-.tabs-newtab-button:-moz-lwtheme-brighttext {
-  background-image: linear-gradient(hsla(0,0%,60%,.6), hsla(0,0%,40%,.6) 4px, hsla(0,0%,30%,.6) 80%);
-}
-
-.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]):hover,
-.tabs-newtab-button:-moz-lwtheme-brighttext:hover {
-  background-image: linear-gradient(hsla(0,0%,80%,.6), hsla(0,0%,60%,.6) 4px, hsla(0,0%,45%,.6) 80%);
-}
-
-.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]),
-.tabs-newtab-button:-moz-lwtheme-darktext {
-  background-image: linear-gradient(hsla(0,0%,100%,.5), hsla(0,0%,60%,.5) 4px, hsla(0,0%,45%,.5) 80%);
-}
-
-.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]):hover,
-.tabs-newtab-button:-moz-lwtheme-darktext:hover {
-  background-image: linear-gradient(hsla(0,0%,100%,.5), hsla(0,0%,80%,.5) 4px, hsla(0,0%,60%,.5) 80%);
-}
-
-.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) {
-  background-image: radial-gradient(circle farthest-corner at 50% 3px, rgba(233,242,252,1) 3%, rgba(172,206,255,.75) 40%, rgba(87,151,201,.5) 80%, rgba(87,151,201,0));
-}
-.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]):hover {
-  background-image: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.6) 2px, hsla(0,0%,75%,.2) 80%),
-                    radial-gradient(circle farthest-corner at 50% 3px, rgba(233,242,252,1) 3%, rgba(172,206,255,.75) 40%, rgba(87,151,201,.5) 80%, rgba(87,151,201,0));
-}
-
-#tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab > .tab-stack > .tab-content[pinned] {
-  min-height: 18px; /* corresponds to the max. height of non-textual tab contents, i.e. the tab close button */
-}
-
-.tabbrowser-tab:focus > .tab-stack {
+.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label {
   outline: 1px dotted;
 }
 
-.tab-throbber,
-.tab-icon-image {
-  width: 16px;
-  height: 16px;
-  -moz-margin-end: 3px;
-  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
-}
-
-.tab-throbber {
-  list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png");
-}
-
-.tab-throbber[progress] {
-  list-style-image: url("chrome://browser/skin/tabbrowser/loading.png");
-}
-
-.tab-throbber[pinned],
-.tab-icon-image[pinned],
-.tabs-newtab-button > .toolbarbutton-icon {
-  -moz-margin-start: 2px;
-  -moz-margin-end: 2px;
-}
-
 #context_reloadTab {
   list-style-image: url("moz-icon://stock/gtk-refresh?size=menu");
 }
 
 #context_closeOtherTabs {
   list-style-image: url("moz-icon://stock/gtk-clear?size=menu");
 }
 
@@ -1753,32 +1688,32 @@ richlistitem[type~="action"][actiontype=
 
 #context_closeTab {
   list-style-image: url("moz-icon://stock/gtk-close?size=menu");
 }
 
 /* Tab drag and drop */
 .tab-drop-indicator {
   list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png);
-  margin-bottom: -11px;
+  margin-bottom: -9px;
+  z-index: 3;
 }
 
 /* In-tab close button */
 .tab-close-button > .toolbarbutton-icon {
   /* XXX Buttons have padding in widget/ that we don't want here but can't override with good CSS, so we must
      use evil CSS to give the impression of smaller content */
   margin: -4px;
 }
 
 .tab-close-button {
-  padding: 0;
   list-style-image: url("moz-icon://stock/gtk-close?size=menu");
-  margin-top: -1px;
+  margin-top: 0;
   margin-bottom: -1px;
-  -moz-margin-end: -1px;
+  -moz-margin-end: -4px;
 }
 
 /* Tabstrip new tab button */
 .tabs-newtab-button,
 #TabsToolbar > #new-tab-button ,
 #TabsToolbar > #wrapper-new-tab-button > #new-tab-button {
   list-style-image: url("moz-icon://stock/gtk-add?size=menu");
   -moz-image-region: auto;
@@ -1889,20 +1824,16 @@ toolbarbutton.chevron > .toolbarbutton-t
 toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
 toolbarbutton.chevron > .toolbarbutton-icon {
   margin: 0;
 }
 
-toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon {
-  display: -moz-box; /* display chevron icon in text mode */
-}
-
 /* Ctrl-Tab */
 
 .ctrlTab-preview {
   -moz-appearance: toolbarbutton;
 }
 
 .tabPreview-canvas {
   box-shadow: 0 0 5px ThreeDShadow;
@@ -1930,54 +1861,16 @@ toolbar[mode="text"] toolbarbutton.chevr
 
 #ctrlTab-showAll {
   -moz-appearance: button;
   color: ButtonText;
   padding: 0 3px;
   margin-top: 10px;
 }
 
-/* Application button menu */
-
-.splitmenu-menuitem {
-  -moz-margin-end: 1px;
-}
-
-#appmenu-toolbar-button:not(:hover):not([open]):not(:-moz-lwtheme) {
-  color: inherit;
-}
-
-#appmenu-toolbar-button > .toolbarbutton-text,
-#appmenu-toolbar-button > .toolbarbutton-menu-dropmarker {
-  margin-top: -2px !important;
-  margin-bottom: -2px !important;
-}
-#appmenuSecondaryPane {
-  -moz-border-start: 1px solid ThreeDShadow;
-}
-#appmenuSecondaryPane-spacer {
-  min-height: 1em;
-}
-#appmenu-cut,
-#appmenu-editmenu-cut {
-  list-style-image: url("moz-icon://stock/gtk-cut?size=menu");
-}
-#appmenu-copy,
-#appmenu-editmenu-copy {
-  list-style-image: url("moz-icon://stock/gtk-copy?size=menu");
-}
-#appmenu-paste,
-#appmenu-editmenu-paste {
-  list-style-image: url("moz-icon://stock/gtk-paste?size=menu");
-}
-#wrapper-appmenu-toolbar-button,
-.appmenu-edit-button[disabled="true"] {
-  opacity: .3;
-}
-
 /* Add-on bar */
 
 #addon-bar {
   box-shadow: 0 1px 0 rgba(0,0,0,.15) inset;
   padding: 0;
   min-height: 20px;
 }
 
@@ -2277,16 +2170,55 @@ toolbar[iconsize="small"] .toolbarbutton
   background-image: radial-gradient(circle farthest-corner at center 3px, rgb(233,242,252) 3%, rgba(172,206,255,0.75) 40%, rgba(87,151,201,0.5) 80%, rgba(87,151,201,0));
 }
 
 chatbox {
   border-top-left-radius: 2.5px;
   border-top-right-radius: 2.5px;
 }
 
+/* Customization mode */
+
+%include ../shared/customizableui/customizeMode.inc.css
+
+#main-window[customizing] #tab-view-deck {
+  background-image: url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"),
+                    url("chrome://browser/skin/customizableui/background-noise-toolbar.png"),
+                    linear-gradient(to bottom, #bcbcbc, #b5b5b5);
+  background-attachment: fixed;
+}
+
+#main-window[customizing] #tab-view-deck {
+  padding: 2em;
+}
+
+#main-window[customizing] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar),
+#main-window[customizing] #customization-container {
+  border: 3px solid hsla(0,0%,0%,.1);
+  border-top-width: 0;
+  background-clip: padding-box;
+  background-origin: padding-box;
+  -moz-border-right-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2);
+  -moz-border-bottom-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2);
+  -moz-border-left-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2);
+}
+
+#main-window[customizing] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
+  border-bottom-width: 0;
+}
+
+#main-window[customizing] #TabsToolbar {
+  -moz-appearance: none;
+  background-clip: padding-box;
+  border-right: 3px solid transparent;
+  border-left: 3px solid transparent;
+}
+
+/* End customization mode */
+
 .click-to-play-plugins-notification-content {
   margin: -10px;
 }
 
 .click-to-play-plugins-notification-icon-box {
   -moz-border-end: 1px solid hsla(0,0%,100%,.2);
   padding-top: 16px;
   -moz-padding-start: 16px;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d09ba9dafb5ede66e92ce577ecaa6f9575dba104
GIT binary patch
literal 15601
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
LNkvXXu0mjfSmbEw
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a7c2775cfc799da31a505b249f5a59b89c148a58
GIT binary patch
literal 118
zc%17D@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3ww^AIAr-gYUfIaWpuppLFlU13
zo%)jzH=|it_dY6Z)V5Pum31fM;KsnRdyNMlls~YU+j}r!!}-)?gCEKjOuj1pzc){H
R6$2W?;OXk;vd$@?2>=UhDL4QC
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5e17cb4db08e310e6c3a9e14c5bd722772dfb639
GIT binary patch
literal 1426
zc$@)}1#S9?P)<h;3K|Lk000e1NJLTq00H0t000aK1^@s6x+QMd000G9Nkl<ZcwX(B
zO>g8j42Jp2&TP87-2_FZ*z`~YX#f8&$|0v-TD03O+GIW~_Au6rWZI@|*6s|(0=Oef
z<V%hN>?7I<zJ2)NCprvAU4sc?4Z&YAsqGrtL{MTBO{tKpXU?nV*0rS?|0gxWT$4Rk
zkDq6Nu6OXn`raBhV?2-0_U3vZGP6O?P^%%gJ+DtHfU3z^dAVgB<XdX;8F{>6-g3=8
z#sk;;h`5Ij-#^|G5f#TWiW4lD8x^whqh#Wuxx}uaD}y=tQ2h$Y0e5uiL<09ifHnU#
zGmA_)={O5VPW94tmGYFkWHq({k?Ep`n}Bd<40otN!Hnl8UBM564!pS@pN%O<Pbd*d
zft6k>^cwWr;FGJWH56^iUiAxVNY_!3*S`zWWypI|h0Q&Pl6nxug~ff)Ask{N|0o70
zU(|K)2nWE{pR_|*^#s(KAbeauu4+)$qNVGiBDWB;q!32LB8CMt0-;$2NC!C5Dr8Jq
z1n^7HWB}e-LBmBZQJlg|HyfQ;*|f_$6Q7u`0JN72W(f^gVd*D*=mEoRHi*J^>g!ri
z;i|JAgJM&N?JI?U7{GJL8LF1L(fB~kx%vaa7d>1*64%FIhtv<EQRqGv@<+Iapt!C8
z?Oj;gg<Ju)KKKM3xE<mB!{h3Ph?rwYlqm?f4SFoyxz~$`xgRcR4Fb|bpb=^+WDz|e
zEX9BJY=IIF1r8e;>45NpOrtOn+bOOlycd`ERQIZ$uvfZ^H#A~4=gR!;x)F-pLj)#j
z{GqLcF0BXrNTwAfP|{NS4!EW{0S)%@tk4BY+4c71+56KLXxE{Q)7;ZG=p1n?wSfkJ
zW55QN?V%HYBiaC|4~X#byU%482xa%e>2!4?m+OmFB%?u#Q%BcLn~+a|WG<{ra)U72
zb4VGC7*-+-S`)#=jfP|~sz7(fEL;W*9i--4!N5;L!DcBas|vtIb+;05x&lO~LT_a|
ztnB){5(st=B(mG%Dx}MHM+6Cf9mwPf=+-4fb#5XVq<Ud@lYrF=EyQ}Sr#V2lzyDk&
z0KApJk)RCru4j*3FB8QAn;u7UC%EO(O}JjwR|DEi=ILm_{o+o~dDA648hkuumslEP
z7rXo>d_P#&&w^XXXdN(mjQ}RQ$$%0gmUf=D4QxV>M}7f5#}9;I@K545U3>B!@LS>+
zT|&kuGBq?I{9=p1i%wwUZ`Xi35k9Qft_G+Z4v24Bh{Rzhip$kwE%!iU*Q@g`{9^^A
ztljR$S~2syl4Q0^bk(*p<X`N(EeAGR!#iMGem~du1YwfL&33?Vh&Ea*l>4OBpu$vT
z^lKC=onCV~YYozQd(NG5HT>{btl{FhSo;HClHVJ~-QABhfTMf;NkAvR6ZL*v2g_^*
zK{!Nc_C7sCD7lq7ZKQQl-(G{gW1XpnTUy37+nZei!2kKa+~?MS(P?1^pY%=8_D_DC
zHy=oVadFP&#>qTisRfW-YhQXh+~323b6OqJrzlSIUupo;dhLcn@1b$+y&nV%J5=tY
zxYpdc`>r+jr+GRvd0?3<@63?5YAv>O&vro1U$YJri}~!lUkAckf=Ywd5cr$@TnaY-
z+t{B;&`BYw`AaLy!{jCRJ==5K*FUAIPn0+Idm22vr%|J-!pxj=JqK{);lylur$0ZC
zucZcQcXVFk&okjBuCfN%8QRS`H|zcRRfCOg5@Nd9bCzWuR9+M?3OLSV2wmW1+0Vv!
z<?!${MpDt7hVFE+qpD~bi-nHkBFzrTF~Auf^P-B9Z9LQRC-LJ9be+S|G8VHP0ME#t
gX&H-M9>A9IFDL!=ycbq6DF6Tf07*qoM6N<$g5jpFQvd(}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dc4caee812878f246c87d71093768eb36c5656fc
GIT binary patch
literal 1649
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01a251f2676fb00c60b26242b23ee8f078dd82ce
GIT binary patch
literal 18635
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
N002ovPDHLkV1jrpBgOy#
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2498e993baf8117fe6788cb98e4be8d039c47bdd
GIT binary patch
literal 1586
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
new file mode 100644
--- /dev/null
+++ b/browser/themes/linux/customizableui/panelUIOverlay.css
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+%filter substitution
+%define menuPanelWidth 23em
+
+%include ../../shared/customizableui/panelUIOverlay.inc.css
+
+#PanelUI-cut-btn {
+  list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar");
+}
+#PanelUI-cut-btn[disabled="true"] {
+  list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar&state=disabled");
+}
+
+#PanelUI-copy-btn {
+  list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar");
+}
+#PanelUI-copy-btn[disabled="true"] {
+  list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar&state=disabled");
+}
+
+#PanelUI-paste-btn {
+  list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar");
+}
+#PanelUI-paste-btn[disabled="true"] {
+  list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar&state=disabled");
+}
+
+#PanelUI-zoomOut-btn {
+  list-style-image: url("moz-icon://stock/gtk-zoom-out?size=toolbar");
+  padding-left: 12px;
+  padding-right: 12px;
+}
+
+#PanelUI-zoomIn-btn {
+  list-style-image: url("moz-icon://stock/gtk-zoom-in?size=toolbar");
+  padding-left: 12px;
+  padding-right: 12px;
+}
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -13,18 +13,26 @@ browser.jar:
   skin/classic/browser/aboutCertError_sectionCollapsed.png
   skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
   skin/classic/browser/aboutCertError_sectionExpanded.png
   skin/classic/browser/aboutSocialError.css
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/aboutSyncTabs.css
 #endif
   skin/classic/browser/actionicon-tab.png
+  skin/classic/browser/appmenu.png
 * skin/classic/browser/browser.css
+* skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/click-to-play-warning-stripes.png
+  skin/classic/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
+  skin/classic/browser/customizableui/customizeMode-gridTexture.png  (customizableui/customizeMode-gridTexture.png)
+  skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png  (customizableui/customizeMode-separatorHorizontal.png)
+  skin/classic/browser/customizableui/customizeMode-separatorVertical.png  (customizableui/customizeMode-separatorVertical.png)
+  skin/classic/browser/customizableui/menuPanel-icons.png (customizableui/menuPanel-icons.png)
+  skin/classic/browser/customizableui/menuPanel-small-icons.png (customizableui/menuPanel-small-icons.png)
 * skin/classic/browser/engineManager.css
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/Go-arrow.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
   skin/classic/browser/identity-icons-https-ev.png
@@ -52,16 +60,17 @@ browser.jar:
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/slowStartup-16.png
   skin/classic/browser/Toolbar.png
   skin/classic/browser/Toolbar-small.png
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/webRTC-shareDevice-16.png
   skin/classic/browser/webRTC-shareDevice-64.png
   skin/classic/browser/webRTC-sharingDevice-16.png
+* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
   skin/classic/browser/downloads/buttons.png          (downloads/buttons.png)
   skin/classic/browser/downloads/download-glow.png    (downloads/download-glow.png)
   skin/classic/browser/downloads/download-glow-small.png (downloads/download-glow-small.png)
   skin/classic/browser/downloads/download-notification-finish.png (downloads/download-notification-finish.png)
   skin/classic/browser/downloads/download-notification-start.png (downloads/download-notification-start.png)
   skin/classic/browser/downloads/download-summary.png (downloads/download-summary.png)
   skin/classic/browser/downloads/downloads.css        (downloads/downloads.css)
   skin/classic/browser/downloads/allDownloadsViewOverlay.css   (downloads/allDownloadsViewOverlay.css)
@@ -108,18 +117,25 @@ browser.jar:
   skin/classic/browser/social/services-16.png         (social/services-16.png)
   skin/classic/browser/social/services-64.png         (social/services-64.png)
   skin/classic/browser/social/share-button.png        (social/share-button.png)
   skin/classic/browser/social/share-button-active.png (social/share-button-active.png)
   skin/classic/browser/social/chat-close.png          (social/chat-close.png)
   skin/classic/browser/tabbrowser/connecting.png      (tabbrowser/connecting.png)
   skin/classic/browser/tabbrowser/loading.png         (tabbrowser/loading.png)
   skin/classic/browser/tabbrowser/tab.png             (tabbrowser/tab.png)
-  skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png)
-  skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
+  skin/classic/browser/tabbrowser/tab-active-middle.png     (tabbrowser/tab-active-middle.png)
+  skin/classic/browser/tabbrowser/tab-background-end.png    (tabbrowser/tab-background-end.png)
+  skin/classic/browser/tabbrowser/tab-background-middle.png (tabbrowser/tab-background-middle.png)
+  skin/classic/browser/tabbrowser/tab-background-start.png  (tabbrowser/tab-background-start.png)
+  skin/classic/browser/tabbrowser/tab-overflow-border.png   (tabbrowser/tab-overflow-border.png)
+  skin/classic/browser/tabbrowser/tab-stroke-end.png        (tabbrowser/tab-stroke-end.png)
+  skin/classic/browser/tabbrowser/tab-stroke-start.png      (tabbrowser/tab-stroke-start.png)
+  skin/classic/browser/tabbrowser/tabDragIndicator.png      (tabbrowser/tabDragIndicator.png)
+  skin/classic/browser/tabbrowser/tab-separator.png         (tabbrowser/tab-separator.png)
   skin/classic/browser/tabview/edit-light.png         (tabview/edit-light.png)
   skin/classic/browser/tabview/search.png             (tabview/search.png)
   skin/classic/browser/tabview/stack-expander.png     (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png            (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css            (tabview/tabview.css)
 * skin/classic/browser/devtools/common.css            (devtools/common.css)
   skin/classic/browser/devtools/dark-theme.css        (devtools/dark-theme.css)
   skin/classic/browser/devtools/light-theme.css       (devtools/light-theme.css)
new file mode 100644
--- /dev/null
+++ b/browser/themes/linux/linuxShared.inc
@@ -0,0 +1,10 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+%filter substitution
+
+%define toolbarHighlight rgba(255,255,255,.3)
+%define fgTabTexture linear-gradient(transparent 0px, transparent 2px, hsla(0,0%,100%,0.35) 2px, hsla(0,0%,100%,0.35) 3px, hsla(0,0%,100%,0.65) 3px, hsla(0,0%,100%,0.65) 4px, @toolbarHighlight@)
+%define fgTabTextureLWT @fgTabTexture@
+%define fgTabBackgroundMiddle @fgTabTexture@, linear-gradient(transparent 0px, transparent 2px, -moz-dialog 2px, -moz-dialog)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6c903ae15688e88e50e9ce817afdc0cbab17ea24
GIT binary patch
literal 96
zc%17D@N?(olHy`uVBq!ia0vp^j6f{U!3HGNPA*RZQtF;Ajv*Dd&K}>$$-uzDd~iL>
u_6>e-W!~-gWm&$#(jvz>jNhZM_7GE+SNM9@YkC<#EexKnelF{r5}E*7of}&K
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..78a4f1f1cbb8d9395750d1e2cef78ae9e82838b9
GIT binary patch
literal 721
zc$@*z0xtcDP)<h;3K|Lk000e1NJLTq0015U0018d1^@s6@N9ht0007*Nkl<Zc-pns
z+e?#i9LMoTx4DCdG`CrsJGi+y+M3!<Z93;{t5!Ol;*t@RL_!1+6?oxAH{Apg1YPtW
zL_r6lf-nk-4&+4?SW=NmRQ3-Tj2-%X;dx*eq3-uQUA%smdq2PL@8P$NlW7bZo(hzp
z06En1YIvNKXz_s;+~5EMG=K^eAQK*-R4Q>&q2=(e)!$Q}zkJO;e)4Q=cJ9KSMy)-7
zP#5Sy1#%%yBncM^g+WL_5{8S#;>6n8pWO2ouQQqKbd;Y$Gt@~L=MWnBhd8A2`TU`q
zx9+7IT5UnZOhR0$aC99p82PsHJ?n6XBM7!j6{m3j2BMI}J22VO*0q~IcZJwEg(I8L
z2Z@)j7BYx=Kn-%S;qWF!AT@LHTmnIh*pX8>RD}peKB{ao(|Ol}TueAng&@SIXHF*(
zG>SQE3j3-Qy8m$gAb;Db#DsTM$%hLjxkcxQ@mH&iHQd7>JT`fh#%&PB%@X!9@L#@i
z?Er!<P_m4h!X5_QkLI7!jsvXcOv?@io*zF~qlgWH24pN@7bCyb>EDN73n*B^4n{k(
zx#KAWtt>AXEp|q(i<hp_j=Nc2Fj_hob-r16JAhc6<(z4;FtUQz<_gj+rmc3|w3tM&
zpE@&_;;&Dou<LTU%x#3iMiI;(mp+B-8ck^g8!NvwHWN08)R{YSg2vqoYGK!8qwqG7
zjLXX_A$_}h6fs-H$ZOYo09y1CFkQcKXGq;_8Ar$g>dHR@yc&TJ)=EGJ*4uX<#PL&@
z;yus+YEV`_gb=52t3<S5dG~&?e`4y`Fg|<)0?-LYXsS4Wj>0VxYXj%vho!!=v*-5@
z?j28idSjXG7Vi*(Zm1W+&HsrGI=}@UaDo}ptrY$Xsi^vbGE;I800000NkvXXu0mjf
Dz`;ej
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c0b65dad63471961c4aa942a69f4733372c2c7cf
GIT binary patch
literal 161
zc%17D@N?(olHy`uVBq!ia0vp^Y(Ol}0V0ox?vVykk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*D5XoIPC}Lp07OCqA3>DCq!GL_>t|>Lc&<{Wp03`ThO9VHl^I
z+p+&U-YCRAlK)!rN4lnr;c!>U;(wP8J~!dl-c;kaG=zyk^n_B^;swh4fW|R+y85}S
Ib4q9e0C=@I!T<mO
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..300dc1d757171af84e84267853aba9c450388b8f
GIT binary patch
literal 705
zc$@*j0zUnTP)<h;3K|Lk000e1NJLTq0015U0018d1^@s6@N9ht0007rNkl<Zc-pns
z-Ahwp90%~VIp^kPTh3XVdvSVnv~|?nW}D7!wq<KN-NYp$D2ap!A}a90i*C9JA_%(Z
zKZt@}hzi0;D0(3;qQH`hOd_>^z+mj9ukgrOLT%?cr;E?U9?tW8&+qqp7@I_<GKy^*
zAtkCn4hpCN)doqSP!LT?pbX?BNDW3{zzHmLix>!`LK0|zc8$KpGd**0|C6WBMn8Y~
znqFP|Ie|S##15?nEilRSWZ?OW*U9zuUzvP9KbFhoh9C+N2#FKSg__m%cJHm*_Y>J{
z_Amlt5QhG(#0+g>oId}z<?m@6JPbhy{EZl)axmx`+xKCH<2W=*4)6OHp}|$41lP+~
z^GO^SfnM;JBSwp@Q>V^H$UObvtAx;MYZY}CKUzFOLVGGDbhf6+sWVY>bG_iHl#t*W
zU>`i1jgu<6`JfG!fqHub6T}xplpMB~5B|Yin~kI6$D-u2bn->pW(7E|T)ln>hq!^|
zOUQgZk7wsLD((OmU$pa8LFmWIS^(=V*v%JBupD%@HuoUb+~A-=d$DZk%!wG*_5eeJ
z_F{Ehx_oVrynPD|+WCgx%)jl&dMh;3plP$-?(oL3#)1v3G$h4hv7FLs6~LZ8I};-<
zGt;Upl&e-#tuZG)E`IW1vjt4F%7=2*DxoWL^kkgO)+j`|Kxs*f?S>}j$kNhs4|(gI
zLU2JG>6RbmN??>)YwE_$y90RM3<jaN&_BZzBv1{V_{o~ObMIjo8*I=3dZ9}H@5rDI
zOwbA*7#^EAKJ@PWLLVNsl1=qu*bJ@(=PoNd;OYt{LkCicbJG_NE__(*#Y1h-2s$xs
n2JgTJ3kh+71DZ)&wg1C!qPhBl8*`*i00000NkvXXu0mjfgAqxS
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..63f77f1b760b2e66e2fab7e739979b7cdede2116
GIT binary patch
literal 192
zc%17D@N?(olHy`uVBq!ia0vp^%s?#1!3HE>CM@{{q$EpRBT9nv(@M${i&7aJQ}UBi
z6+Ckj(^G>|6H_V+Po~-c6(xDPIEGZ*O8WEvzdbXLfuRE9vh(lf8+&zsHf+wAz@sd%
zxhX@Uo%a}HqL@H$XdAB@^C6iNr*2G~T9^>pb}-TXSwYfM1Lv;>$)*jHEvhXFqq^=|
nO8iSata-RghnX+10qCqHCR~QDO&0Ay+Za4u{an^LB{Ts5X9_^D
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6d9e07ddfdb2012daaac0159b313dd4cc32fcc36
GIT binary patch
literal 473
zc$@**0Ve*5P)<h;3K|Lk000e1NJLTq0015U0018d1^@s6@N9ht0004?Nkl<Zc-p;|
z+fKqj5Qc#swp$FAAku}lXpONP%AwU8F=*h9sPF$a_&1rRWWCUfcA9*>ASB<+{JY(4
zbvhkE*n~xxzyQV5CR%@SKA-<Z%bn&Q?lgOIqwLj<wz&+}3rEcZ+f!Fm$gcuw5#v?J
zO(1{=6qtdX3^!}Xe;R28kh})54i(b|Ly*gGy>xCL2NXfoea&LMfC2^fa<aT5dDVFX
zV!ePa*g<|@%2~uDcfsCKiBFl+$Qu@u{056IqXlQMiAkPf<S~t$y5<qP;Aoh(pssnu
zB;R6>E3Io5vBLh|lv#6%4RAEwYYCyrCMNka#$9bKM)89T(&RE{F7eO}H!oVwEMkEp
z^+4yj$tEWG!S=?zGG|V4?x-Zxa%K_7GFYWr&Me{{u1xP`&P?JeXEBKS+UJu+JjZF3
zl;h?UcfproT2i|pG%F@~CMW3vGX1D*Tr9!K@smg&Inj)m<UaVu!7<V07t}8%`51f_
zi_Nfv&@(4$73)`{44m+BNgOrni(xFR-iQjQ#7!0ugB1vXN57f$Cw_ha0p<l376E0{
P00000NkvXXu0mjf|FG5w
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a741942ac8db0dc46bf22ccfe20b81c8df7456f5
GIT binary patch
literal 483
zc$@*_0UZ8`P)<h;3K|Lk000e1NJLTq0015U0018d1^@s6@N9ht00051Nkl<Zc-p<z
z{Y%0?9LMo=x83dxo0z$C57r`_4|BTJFBKK`TU7u5e`BA)!55s6FmHo52%dX!cYE++
zzu%u!x7$6Xj;=Z^#E`9XbiAqo{4eM@p1O3^A{1f1l<~Hdaq%pt#jBi_AB|x`33UD0
zSVWr~zzdoqg*?O&tIpR5KA5HL-aHINl&^5|5{*#j*twd*G*h4=Slt48)3c-B8i5JD
z)63e^;|;;I#LQKxuV*T0yjj>n4lbes=rxTs0@G~u5+^`28fPB1Eaq^apGdX<(`<3C
zDxg~$V;H8r%{PEmn=oVYO6X;_+JdWtVVQlPkMzA+n6Bn9O99^-hU@z)qs<fGQJXMB
z9Iv(=VBP{u`|Eg<KF}R~Zx*KeSEUi)(llJZf5UYKIB5%}{f)QpfcpmF`eTw0;{olj
zd6<?tSfzj$CgIu(-(t1^`h$9=;A1a*E`n?cv}guWC;iKC{WJ#pg~S<Q0*|A!0N^k3
zn}ZZ#hkI&st}mu<G&v_qFhILM?($K>T{R!zA(85(E$FY!nPHrmA&EQ`qBTkgG?V_&
Zet+r)1r}%yr}6**002ovPDHLkV1g-9;KTp`
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..aab0a02c84d63603ec1fc3a385a08c5cf5360fd2
GIT binary patch
literal 15667
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