Bug 1500268 - remove legacy toolbar and currentset support from customizableui, r=jaws
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Mon, 22 Oct 2018 16:02:07 +0000
changeset 442414 c78192e00cf32a15c41d57eabdec3c1687348d17
parent 442413 9b894301f1fd348275e16569334aef00a336a751
child 442415 a67cc39bf78a77bd030cbb4a8ed1e5ce8e9c1baa
push id34907
push userebalazs@mozilla.com
push dateTue, 23 Oct 2018 09:23:56 +0000
treeherdermozilla-central@dfa1eb1d036f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1500268
milestone64.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
Bug 1500268 - remove legacy toolbar and currentset support from customizableui, r=jaws Differential Revision: https://phabricator.services.mozilla.com/D9172
browser/base/content/browser.css
browser/components/customizableui/CustomizableUI.jsm
browser/components/customizableui/CustomizeMode.jsm
browser/components/customizableui/content/toolbar.xml
browser/components/customizableui/test/browser.ini
browser/components/customizableui/test/browser_887438_currentset_shim.js
browser/components/customizableui/test/browser_888817_currentset_updating.js
browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js
browser/components/customizableui/test/browser_913972_currentset_overflow.js
browser/components/customizableui/test/browser_940013_registerToolbarNode_calls_registerArea.js
browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js
browser/components/customizableui/test/browser_currentset_post_reset.js
browser/components/nsBrowserGlue.js
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -67,17 +67,17 @@
 }
 
 toolbar[customizable="true"] {
   -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar");
 }
 
 %ifdef XP_MACOSX
 #toolbar-menubar {
-  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-stub");
+  -moz-binding: none;
 }
 %endif
 
 panelmultiview {
   -moz-box-align: start;
 }
 
 panelmultiview[transitioning] {
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -204,46 +204,42 @@ var CustomizableUIInternal = {
       "sidebar-button",
     ];
 
     if (AppConstants.MOZ_DEV_EDITION) {
       navbarPlacements.splice(2, 0, "developer-button");
     }
 
     this.registerArea(CustomizableUI.AREA_NAVBAR, {
-      legacy: true,
       type: CustomizableUI.TYPE_TOOLBAR,
       overflowable: true,
       defaultPlacements: navbarPlacements,
       defaultCollapsed: false,
     }, true);
 
     if (AppConstants.MENUBAR_CAN_AUTOHIDE) {
       this.registerArea(CustomizableUI.AREA_MENUBAR, {
-        legacy: true,
         type: CustomizableUI.TYPE_TOOLBAR,
         defaultPlacements: [
           "menubar-items",
         ],
         defaultCollapsed: true,
       }, true);
     }
 
     this.registerArea(CustomizableUI.AREA_TABSTRIP, {
-      legacy: true,
       type: CustomizableUI.TYPE_TOOLBAR,
       defaultPlacements: [
         "tabbrowser-tabs",
         "new-tab-button",
         "alltabs-button",
       ],
       defaultCollapsed: null,
     }, true);
     this.registerArea(CustomizableUI.AREA_BOOKMARKS, {
-      legacy: true,
       type: CustomizableUI.TYPE_TOOLBAR,
       defaultPlacements: [
         "personal-bookmarks",
       ],
       defaultCollapsed: true,
     }, true);
 
     SearchWidgetTracker.init();
@@ -585,17 +581,17 @@ var CustomizableUIInternal = {
 
   registerArea(aName, aProperties, aInternalCaller) {
     if (typeof aName != "string" || !/^[a-z0-9-_]{1,}$/i.test(aName)) {
       throw new Error("Invalid area name");
     }
 
     let areaIsKnown = gAreas.has(aName);
     let props = areaIsKnown ? gAreas.get(aName) : new Map();
-    const kImmutableProperties = new Set(["type", "legacy", "overflowable"]);
+    const kImmutableProperties = new Set(["type", "overflowable"]);
     for (let key in aProperties) {
       if (areaIsKnown && kImmutableProperties.has(key) &&
           props.get(key) != aProperties[key]) {
         throw new Error("An area cannot change the property for '" + key + "'");
       }
       props.set(key, aProperties[key]);
     }
     // Default to a toolbar:
@@ -630,17 +626,17 @@ var CustomizableUIInternal = {
     }
 
     if (!areaIsKnown) {
       gAreas.set(aName, props);
 
       // Reconcile new default widgets. Have to do this before we start restoring things.
       this._placeNewDefaultWidgetsInArea(aName);
 
-      if (props.get("legacy") && !gPlacements.has(aName)) {
+      if (props.get("type") == CustomizableUI.TYPE_TOOLBAR && !gPlacements.has(aName)) {
         // Guarantee this area exists in gFuturePlacements, to avoid checking it in
         // various places elsewhere.
         if (!gFuturePlacements.has(aName)) {
           gFuturePlacements.set(aName, new Set());
         }
       } else {
         this.restoreStateForArea(aName);
       }
@@ -702,44 +698,29 @@ var CustomizableUIInternal = {
     let area = aToolbar.id;
     if (gBuildAreas.has(area) && gBuildAreas.get(area).has(aToolbar)) {
       return;
     }
     let areaProperties = gAreas.get(area);
 
     // If this area is not registered, try to do it automatically:
     if (!areaProperties) {
-      // If there's no default set attribute at all, we assume that we should
-      // wait for registerArea to be called:
-      if (!aToolbar.hasAttribute("defaultset")) {
-        if (!gPendingBuildAreas.has(area)) {
-          gPendingBuildAreas.set(area, new Map());
-        }
-        let pendingNodes = gPendingBuildAreas.get(area);
-        pendingNodes.set(aToolbar, aExistingChildren);
-        return;
+      if (!gPendingBuildAreas.has(area)) {
+        gPendingBuildAreas.set(area, new Map());
       }
-      let props = {type: CustomizableUI.TYPE_TOOLBAR, legacy: true};
-      let defaultsetAttribute = aToolbar.getAttribute("defaultset") || "";
-      props.defaultPlacements = defaultsetAttribute.split(",").filter(s => s);
-      this.registerArea(area, props);
-      areaProperties = gAreas.get(area);
+      let pendingNodes = gPendingBuildAreas.get(area);
+      pendingNodes.set(aToolbar, aExistingChildren);
+      return;
     }
 
     this.beginBatchUpdate();
     try {
       let placements = gPlacements.get(area);
-      if (!placements && areaProperties.has("legacy")) {
-        let legacyState = aToolbar.getAttribute("currentset");
-        if (legacyState) {
-          legacyState = legacyState.split(",").filter(s => s);
-        }
-
-        // Manually restore the state here, so the legacy state can be converted.
-        this.restoreStateForArea(area, legacyState);
+      if (!placements && areaProperties.get("type") == CustomizableUI.TYPE_TOOLBAR) {
+        this.restoreStateForArea(area);
         placements = gPlacements.get(area);
       }
 
       // Check that the current children and the current placements match. If
       // not, mark it as dirty:
       if (aExistingChildren.length != placements.length ||
           aExistingChildren.every((id, i) => id == placements[i])) {
         gDirtyAreaCache.add(area);
@@ -758,17 +739,16 @@ var CustomizableUIInternal = {
       //    the placements array for that area.
       //
       // This notion of being "dirty" is stored in a cache which is persisted
       // in the saved state.
       if (gDirtyAreaCache.has(area)) {
         this.buildArea(area, placements, aToolbar);
       }
       this.notifyListeners("onAreaNodeRegistered", area, aToolbar.customizationTarget);
-      aToolbar.setAttribute("currentset", placements.join(","));
     } finally {
       this.endBatchUpdate();
     }
   },
 
   buildArea(aArea, aPlacements, aAreaNode) {
     let document = aAreaNode.ownerDocument;
     let window = document.defaultView;
@@ -1069,20 +1049,16 @@ var CustomizableUIInternal = {
       this.ensureButtonContextMenu(widgetNode);
       if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
         container.removeChild(widgetNode);
       } else {
         window.gNavToolbox.palette.appendChild(widgetNode);
       }
       this.notifyListeners("onWidgetAfterDOMChange", widgetNode, null, container, true);
 
-      if (isToolbar) {
-        areaNode.setAttribute("currentset", gPlacements.get(aArea).join(","));
-      }
-
       let windowCache = gSingleWrapperCache.get(window);
       if (windowCache) {
         windowCache.delete(aWidgetId);
       }
     }
     if (!gResetting) {
       this._clearPreviousUIState();
     }
@@ -1237,20 +1213,16 @@ var CustomizableUIInternal = {
 
     let areaId = aAreaNode.id;
     if (isNew) {
       this.ensureButtonContextMenu(widgetNode, aAreaNode);
     }
 
     let [insertionContainer, nextNode] = this.findInsertionPoints(widgetNode, aAreaNode);
     this.insertWidgetBefore(widgetNode, nextNode, insertionContainer, areaId);
-
-    if (gAreas.get(areaId).get("type") == CustomizableUI.TYPE_TOOLBAR) {
-      aAreaNode.setAttribute("currentset", gPlacements.get(areaId).join(","));
-    }
   },
 
   findInsertionPoints(aNode, aAreaNode) {
     let areaId = aAreaNode.id;
     let props = gAreas.get(areaId);
 
     // For overflowable toolbars, rely on them (because the work is more complicated):
     if (props.get("type") == CustomizableUI.TYPE_TOOLBAR && props.get("overflowable")) {
@@ -2017,20 +1989,18 @@ var CustomizableUIInternal = {
     gDirtyAreaCache.add(oldPlacement.area);
 
     this.saveState();
 
     this.notifyListeners("onWidgetMoved", aWidgetId, oldPlacement.area,
                          oldPlacement.position, aPosition);
   },
 
-  // Note that this does not populate gPlacements, which is done lazily so that
-  // the legacy state can be migrated, which is only available once a browser
-  // window is openned.
-  // The panel area is an exception here, since it has no legacy state.
+  // Note that this does not populate gPlacements, which is done lazily.
+  // The panel area is an exception here.
   loadSavedState() {
     let state = Services.prefs.getCharPref(kPrefCustomizationState, "");
     if (!state) {
       log.debug("No saved state found");
       // Nothing has been customized, so silently fall back to the defaults.
       return;
     }
     try {
@@ -2052,17 +2022,17 @@ var CustomizableUIInternal = {
       gSavedState.currentVersion = 0;
     }
 
     gSeenWidgets = new Set(gSavedState.seen || []);
     gDirtyAreaCache = new Set(gSavedState.dirtyAreaCache || []);
     gNewElementCount = gSavedState.newElementCount || 0;
   },
 
-  restoreStateForArea(aArea, aLegacyState) {
+  restoreStateForArea(aArea) {
     let placementsPreexisted = gPlacements.has(aArea);
 
     this.beginBatchUpdate();
     try {
       gRestoring = true;
 
       let restored = false;
       if (placementsPreexisted) {
@@ -2080,25 +2050,16 @@ var CustomizableUIInternal = {
         log.debug("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.debug("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.debug("Restoring " + aArea + " from default state");
         let defaults = gAreas.get(aArea).get("defaultPlacements");
         if (defaults) {
           for (let id of defaults)
             this.addWidgetToArea(id, aArea, null, true);
         }
         gDirty = false;
@@ -2377,17 +2338,17 @@ var CustomizableUIInternal = {
     }
   },
 
   // Returns true if the area will eventually lazily restore (but hasn't yet).
   isAreaLazy(aArea) {
     if (gPlacements.has(aArea)) {
       return false;
     }
-    return gAreas.get(aArea).has("legacy");
+    return gAreas.get(aArea).get("type") == CustomizableUI.TYPE_TOOLBAR;
   },
 
   // XXXunf Log some warnings here, when the data provided isn't up to scratch.
   normalizeWidget(aData, aSource) {
     let widget = {
       implementation: aData,
       source: aSource || CustomizableUI.SOURCE_EXTERNAL,
       instances: new Map(),
@@ -2807,61 +2768,78 @@ var CustomizableUIInternal = {
     if (existingNode) {
       return true;
     }
 
     this.insertNodeInWindow(aWidgetId, container[0], true);
     return true;
   },
 
+  _getCurrentWidgetsInContainer(container) {
+    // Get a list of all the widget IDs in this container, including any that
+    // are overflown.
+    let currentWidgets = new Set();
+    function addUnskippedChildren(parent) {
+      for (let node of parent.children) {
+        let realNode = node.localName == "toolbarpaletteitem" ? node.firstElementChild : node;
+        if (realNode.getAttribute("skipintoolbarset") != "true") {
+          currentWidgets.add(realNode.id);
+        }
+      }
+    }
+    addUnskippedChildren(container.customizationTarget);
+    if (container.getAttribute("overflowing") == "true") {
+      let overflowTarget = container.getAttribute("overflowtarget");
+      addUnskippedChildren(container.ownerDocument.getElementById(overflowTarget));
+    }
+    // Then get the sorted list of placements, and filter based on the nodes
+    // that are present. This avoids including items that don't exist (e.g. ids
+    // of add-on items that the user has uninstalled).
+    let orderedPlacements = CustomizableUI.getWidgetIdsInArea(container.id);
+    return orderedPlacements.filter(w => currentWidgets.has(w));
+  },
+
   get inDefaultState() {
     for (let [areaId, props] of gAreas) {
       let defaultPlacements = props.get("defaultPlacements");
-      // Areas without default placements (like legacy ones?) get skipped
-      if (!defaultPlacements) {
-        continue;
-      }
-
       let currentPlacements = gPlacements.get(areaId);
       // We're excluding all of the placement IDs for items that do not exist,
       // and items that have removable="false",
       // because we don't want to consider them when determining if we're
       // in the default state. This way, if an add-on introduces a widget
       // and is then uninstalled, the leftover placement doesn't cause us to
       // automatically assume that the buttons are not in the default state.
       let buildAreaNodes = gBuildAreas.get(areaId);
       if (buildAreaNodes && buildAreaNodes.size) {
         let container = [...buildAreaNodes][0];
         let removableOrDefault = (itemNodeOrItem) => {
           let item = (itemNodeOrItem && itemNodeOrItem.id) || itemNodeOrItem;
           let isRemovable = this.isWidgetRemovable(itemNodeOrItem);
           let isInDefault = defaultPlacements.includes(item);
           return isRemovable || isInDefault;
         };
-        // Toolbars have a currentSet property which also deals correctly with overflown
-        // widgets (if any) - use that instead:
+        // Toolbars need to deal with overflown widgets (if any) - so
+        // specialcase them:
         if (props.get("type") == CustomizableUI.TYPE_TOOLBAR) {
-          let currentSet = container.currentSet;
-          currentPlacements = currentSet ? currentSet.split(",") : [];
-          currentPlacements = currentPlacements.filter(removableOrDefault);
+          currentPlacements =
+            this._getCurrentWidgetsInContainer(container).filter(removableOrDefault);
         } else {
-          // Clone the array so we don't modify the actual placements...
-          currentPlacements = [...currentPlacements];
           currentPlacements = currentPlacements.filter((item) => {
             let itemNode = container.getElementsByAttribute("id", item)[0];
             return itemNode && removableOrDefault(itemNode || item);
           });
         }
 
         if (props.get("type") == CustomizableUI.TYPE_TOOLBAR) {
           let attribute = container.getAttribute("type") == "menubar" ? "autohide" : "collapsed";
           let collapsed = container.getAttribute(attribute) == "true";
           let defaultCollapsed = props.get("defaultCollapsed");
           if (defaultCollapsed !== null && collapsed != defaultCollapsed) {
-            log.debug("Found " + areaId + " had non-default toolbar visibility (expected " + defaultCollapsed + ", was " + collapsed + ")");
+            log.debug("Found " + areaId + " had non-default toolbar visibility" +
+                      "(expected " + defaultCollapsed + ", was " + collapsed + ")");
             return false;
           }
         }
       }
       log.debug("Checking default state for " + areaId + ":\n" + currentPlacements.join(",") +
                 "\nvs.\n" + defaultPlacements.join(","));
 
       if (currentPlacements.length != defaultPlacements.length) {
@@ -3113,18 +3091,16 @@ var CustomizableUI = {
    * @param aName   the name of the area to register. Can only contain
    *                alphanumeric characters, dashes (-) and underscores (_).
    * @param aProps  the properties of the area. The following properties are
    *                recognized:
    *                - type:   the type of area. Either TYPE_TOOLBAR (default) or
    *                          TYPE_MENU_PANEL;
    *                - anchor: for a menu panel or overflowable toolbar, the
    *                          anchoring node for the panel.
-   *                - legacy: set to true if you want customizableui to
-   *                          automatically migrate the currentset attribute
    *                - overflowable: set to true if your toolbar is overflowable.
    *                                This requires an anchor, and only has an
    *                                effect for toolbars.
    *                - defaultPlacements: an array of widget IDs making up the
    *                                     default contents of the area
    *                - defaultCollapsed: (INTERNAL ONLY) applies if the type is TYPE_TOOLBAR, specifies
    *                                    if toolbar is collapsed by default (default to true).
    *                                    Specify null to ensure that reset/inDefaultArea don't care
@@ -3137,19 +3113,17 @@ var CustomizableUI = {
    * Register a concrete node for a registered area. This method is automatically
    * called from any toolbar in the main browser window that has its
    * "customizable" attribute set to true. There should normally be no need to
    * call it yourself.
    *
    * Note that ideally, you should register your toolbar using registerArea
    * before any of the toolbars have their XBL bindings constructed (which
    * will happen when they're added to the DOM and are not hidden). If you
-   * don't, and your toolbar has a defaultset attribute, CustomizableUI will
-   * register it automatically. If your toolbar does not have a defaultset
-   * attribute, the node will be saved for processing when you call
+   * don't, the node will be saved for processing when you call
    * registerArea. Note that CustomizableUI won't restore state in the area,
    * allow the user to customize it in customize mode, or otherwise deal
    * with it, until the area has been registered.
    */
   registerToolbarNode(aToolbar, aExistingChildren) {
     CustomizableUIInternal.registerToolbarNode(aToolbar, aExistingChildren);
   },
   /**
@@ -3184,18 +3158,16 @@ var CustomizableUI = {
    */
   unregisterArea(aName, aDestroyPlacements) {
     CustomizableUIInternal.unregisterArea(aName, aDestroyPlacements);
   },
   /**
    * Add a widget to an area.
    * If the area to which you try to add is not known to CustomizableUI,
    * this will throw.
-   * If the area to which you try to add has not yet been restored from its
-   * legacy state, this will postpone the addition.
    * If the area to which you try to add is the same as the area in which
    * the widget is currently placed, this will do the same as
    * moveWidgetWithinArea.
    * If the widget cannot be removed from its original location, this will
    * no-op.
    *
    * This will fire an onWidgetAdded notification,
    * and an onWidgetBeforeDOMChange and onWidgetAfterDOMChange notification
@@ -3465,19 +3437,18 @@ var CustomizableUI = {
    */
   getUnusedWidgets(aWindowPalette) {
     return CustomizableUIInternal.getUnusedWidgets(aWindowPalette).map(
       CustomizableUIInternal.wrapWidget,
       CustomizableUIInternal
     );
   },
   /**
-   * Get an array of all the widget IDs placed in an area. This is roughly
-   * equivalent to fetching the currentset attribute and splitting by commas
-   * in the legacy APIs. Modifying the array will not affect CustomizableUI.
+   * Get an array of all the widget IDs placed in an area.
+   * Modifying the array will not affect CustomizableUI.
    *
    * @param aArea the ID of the area whose placements you want to obtain.
    * @return an array containing the widget IDs that are in the area.
    *
    * NB: will throw if called too early (before placements have been fetched)
    *     or if the area is not currently known to CustomizableUI.
    */
   getWidgetIdsInArea(aArea) {
@@ -3490,19 +3461,18 @@ var CustomizableUI = {
 
     // We need to clone this, as we don't want to let consumers muck with placements
     return [...gPlacements.get(aArea)];
   },
   /**
    * Get an array of widget wrappers for all the widgets in an area. This is
    * the same as calling getWidgetIdsInArea and .map() ing the result through
    * CustomizableUI.getWidget. Careful: this means that if there are IDs in there
-   * which don't have corresponding DOM nodes (like in the old-style currentset
-   * attribute), there might be nulls in this array, or items for which
-   * wrapper.forWindow(win) will return null.
+   * which don't have corresponding DOM nodes, there might be nulls in this array,
+   * or items for which wrapper.forWindow(win) will return null.
    *
    * @param aArea the ID of the area whose widgets you want to obtain.
    * @return an array of widget wrappers and/or null values for the widget IDs
    *         placed in an area.
    *
    * NB: will throw if called too early (before placements have been fetched)
    *     or if the area is not currently known to CustomizableUI.
    */
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -420,24 +420,16 @@ CustomizeMode.prototype = {
       customizer.hidden = true;
 
       window.gNavToolbox.removeEventListener("toolbarvisibilitychange", this);
 
       this._teardownPaletteDragging();
 
       await this._unwrapToolbarItems();
 
-      if (this._changed) {
-        // XXXmconley: At first, it seems strange to also persist the old way with
-        //             currentset - but this might actually be useful for switching
-        //             to old builds. We might want to keep this around for a little
-        //             bit.
-        this.persistCurrentSets();
-      }
-
       // And drop all area references.
       this.areas.clear();
 
       // Let everybody in this window know that we're starting to
       // exit customization mode.
       CustomizableUI.dispatchToolboxEvent("customizationending", {}, window);
 
       window.PanelUI.menuButton.disabled = false;
@@ -1060,47 +1052,32 @@ CustomizeMode.prototype = {
           }
         }
         this._removeDragHandlers(target);
       }
       this.areas.clear();
     })().catch(log.error);
   },
 
-  persistCurrentSets(aSetBeforePersisting) {
-    let document = this.document;
-    let toolbars = document.querySelectorAll("toolbar[customizable='true'][currentset]");
-    for (let toolbar of toolbars) {
-      if (aSetBeforePersisting) {
-        let set = toolbar.currentSet;
-        toolbar.setAttribute("currentset", set);
-      }
-      // Persist the currentset attribute directly on hardcoded toolbars.
-      Services.xulStore.persist(toolbar, "currentset");
-    }
-  },
-
   reset() {
     this.resetting = true;
     // Disable the reset button temporarily while resetting:
     let btn = this.$("customization-reset-button");
     btn.disabled = true;
     return (async () => {
       await this.depopulatePalette();
       await this._unwrapToolbarItems();
 
       CustomizableUI.reset();
 
       this._updateLWThemeButtonIcon();
 
       await this._wrapToolbarItems();
       this.populatePalette();
 
-      this.persistCurrentSets(true);
-
       this._updateResetButton();
       this._updateUndoResetButton();
       this._updateEmptyPaletteNotice();
       this._moveDownloadsButtonToNavBar = false;
       this.resetting = false;
       if (!this._wantToBeInCustomizeMode) {
         this.exit();
       }
@@ -1116,18 +1093,16 @@ CustomizeMode.prototype = {
 
       CustomizableUI.undoReset();
 
       this._updateLWThemeButtonIcon();
 
       await this._wrapToolbarItems();
       this.populatePalette();
 
-      this.persistCurrentSets(true);
-
       this._updateResetButton();
       this._updateUndoResetButton();
       this._updateEmptyPaletteNotice();
       this._moveDownloadsButtonToNavBar = false;
       this.resetting = false;
     })().catch(log.error);
   },
 
--- a/browser/components/customizableui/content/toolbar.xml
+++ b/browser/components/customizableui/content/toolbar.xml
@@ -46,87 +46,16 @@
             this._customizationTarget = document.getElementById(id);
 
           if (!this._customizationTarget)
             this._customizationTarget = this;
 
           return this._customizationTarget;
         ]]></getter>
       </property>
-
-      <property name="currentSet">
-        <getter><![CDATA[
-          let currentWidgets = new Set();
-          for (let node of this.customizationTarget.children) {
-            let realNode = node.localName == "toolbarpaletteitem" ? node.firstElementChild : node;
-            if (realNode.getAttribute("skipintoolbarset") != "true") {
-              currentWidgets.add(realNode.id);
-            }
-          }
-          if (this.getAttribute("overflowing") == "true") {
-            let overflowTarget = this.getAttribute("overflowtarget");
-            let overflowList = this.ownerDocument.getElementById(overflowTarget);
-            for (let node of overflowList.children) {
-              let realNode = node.localName == "toolbarpaletteitem" ? node.firstElementChild : node;
-              if (realNode.getAttribute("skipintoolbarset") != "true") {
-                currentWidgets.add(realNode.id);
-              }
-            }
-          }
-          let orderedPlacements = CustomizableUI.getWidgetIdsInArea(this.id);
-          return orderedPlacements.filter(w => currentWidgets.has(w)).join(",");
-        ]]></getter>
-        <setter><![CDATA[
-          // Get list of new and old ids:
-          let newVal = (val || "").split(",").filter(x => x);
-          let oldIds = CustomizableUI.getWidgetIdsInArea(this.id);
-
-          // Get a list of items only in the new list
-          let newIds = newVal.filter(id => !oldIds.includes(id));
-          CustomizableUI.beginBatchUpdate();
-          try {
-            for (let newId of newIds) {
-              oldIds = CustomizableUI.getWidgetIdsInArea(this.id);
-              let nextId = newId;
-              let pos;
-              do {
-                // Get the next item
-                nextId = newVal[newVal.indexOf(nextId) + 1];
-                // Figure out where it is in the old list
-                pos = oldIds.indexOf(nextId);
-                // If it's not in the old list, repeat:
-              } while (pos == -1 && nextId);
-              if (pos == -1) {
-                pos = null; // We didn't find anything, insert at the end
-              }
-              CustomizableUI.addWidgetToArea(newId, this.id, pos);
-            }
-
-            let currentIds = this.currentSet.split(",");
-            let removedIds = currentIds.filter(id => !newIds.includes(id) && !newVal.includes(id));
-            for (let removedId of removedIds) {
-              CustomizableUI.removeWidgetFromArea(removedId);
-            }
-          } finally {
-            CustomizableUI.endBatchUpdate();
-          }
-        ]]></setter>
-      </property>
-
-
-    </implementation>
-  </binding>
-
-  <binding id="toolbar-menubar-stub">
-    <implementation>
-      <property name="currentSet" readonly="true">
-        <getter><![CDATA[
-          return this.getAttribute("defaultset");
-        ]]></getter>
-      </property>
     </implementation>
   </binding>
 
   <!-- The toolbar-drag binding is almost a verbatim copy of its toolkit counterpart,
        but it inherits from the customizableui's toolbar binding instead of toolkit's.
        This functionality will move into CustomizableUI proper as part of our move
        away from XBL. -->
   <binding id="toolbar-drag"
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -15,18 +15,16 @@ support-files =
 skip-if = os == "linux" || verify
 [browser_885052_customize_mode_observers_disabed.js]
 tags = fullscreen
 # Bug 951403 - Disabled on OSX for frequent failures
 skip-if = os == "mac"
 
 [browser_885530_showInPrivateBrowsing.js]
 [browser_886323_buildArea_removable_nodes.js]
-[browser_887438_currentset_shim.js]
-[browser_888817_currentset_updating.js]
 [browser_890262_destroyWidget_after_add_to_panel.js]
 [browser_892955_isWidgetRemovable_for_removed_widgets.js]
 [browser_892956_destroyWidget_defaultPlacements.js]
 [browser_909779_overflow_toolbars_new_window.js]
 skip-if = os == "linux"
 
 [browser_901207_searchbar_in_panel.js]
 [browser_913972_currentset_overflow.js]
deleted file mode 100644
--- a/browser/components/customizableui/test/browser_887438_currentset_shim.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-var navbar = document.getElementById("nav-bar");
-var navbarCT = navbar.customizationTarget;
-var overflowPanelList = document.getElementById("widget-overflow-list");
-
-// Reading currentset
-add_task(function() {
-  let nodeIds = [];
-  for (let node of navbarCT.children) {
-    if (node.getAttribute("skipintoolbarset") != "true") {
-      nodeIds.push(node.id);
-    }
-  }
-  for (let node of overflowPanelList.children) {
-    if (node.getAttribute("skipintoolbarset") != "true") {
-      nodeIds.push(node.id);
-    }
-  }
-  let currentSet = navbar.currentSet;
-  is(currentSet.split(",").length, nodeIds.length, "Should be just as many nodes as there are.");
-  is(currentSet, nodeIds.join(","), "Current set and node IDs should match.");
-});
-
-// Insert, then remove items
-add_task(function() {
-  let currentSet = navbar.currentSet;
-  let newCurrentSet = currentSet.replace("home-button", "new-window-button,sync-button,home-button");
-  navbar.currentSet = newCurrentSet;
-  is(newCurrentSet, navbar.currentSet, "Current set should match expected current set.");
-  let feedBtn = document.getElementById("new-window-button");
-  let syncBtn = document.getElementById("sync-button");
-  ok(feedBtn, "Feed button should have been added.");
-  ok(syncBtn, "Sync button should have been added.");
-  if (feedBtn && syncBtn) {
-    let feedParent = feedBtn.parentNode;
-    let syncParent = syncBtn.parentNode;
-    ok(feedParent == navbarCT || feedParent == overflowPanelList,
-       "Feed button should be in navbar or overflow");
-    ok(syncParent == navbarCT || syncParent == overflowPanelList,
-       "Feed button should be in navbar or overflow");
-    is(feedBtn.nextElementSibling, syncBtn, "Feed button should be next to sync button.");
-    let homeBtn = document.getElementById("home-button");
-    is(syncBtn.nextElementSibling, homeBtn, "Sync button should be next to home button.");
-  }
-  navbar.currentSet = currentSet;
-  is(currentSet, navbar.currentSet, "Should be able to remove the added items.");
-});
-
-// Simultaneous insert/remove:
-add_task(function() {
-  let currentSet = navbar.currentSet;
-  let newCurrentSet = currentSet.replace("home-button", "new-window-button");
-  navbar.currentSet = newCurrentSet;
-  is(newCurrentSet, navbar.currentSet, "Current set should match expected current set.");
-  let feedBtn = document.getElementById("new-window-button");
-  ok(feedBtn, "Feed button should have been added.");
-  let homeBtn = document.getElementById("home-button");
-  ok(!homeBtn, "Home button should have been removed.");
-  if (feedBtn) {
-    let feedParent = feedBtn.parentNode;
-    ok(feedParent == navbarCT || feedParent == overflowPanelList,
-       "Feed button should be in navbar or overflow");
-  }
-  navbar.currentSet = currentSet;
-  is(currentSet, navbar.currentSet, "Should be able to return to original state.");
-});
-
-add_task(async function asyncCleanup() {
-  await resetCustomization();
-});
deleted file mode 100644
--- a/browser/components/customizableui/test/browser_888817_currentset_updating.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-// Adding, moving and removing items should update the relevant currentset attributes
-add_task(async function() {
-  ok(CustomizableUI.inDefaultState, "Should be in the default state when we start");
-  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
-  setToolbarVisibility(personalbar, true);
-  ok(!CustomizableUI.inDefaultState, "Making the bookmarks toolbar visible takes it out of the default state");
-
-  let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
-  personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
-  let navbarCurrentset = navbar.getAttribute("currentset") || navbar.currentSet;
-  let personalbarCurrentset = personalbar.getAttribute("currentset") || personalbar.currentSet;
-
-  let otherWin = await openAndLoadWindow();
-  let otherNavbar = otherWin.document.getElementById(CustomizableUI.AREA_NAVBAR);
-  let otherPersonalbar = otherWin.document.getElementById(CustomizableUI.AREA_BOOKMARKS);
-
-  CustomizableUI.moveWidgetWithinArea("home-button", 0);
-  navbarCurrentset = "home-button," + navbarCurrentset.replace(",home-button", "");
-  is(navbar.getAttribute("currentset"), navbarCurrentset,
-     "Should have updated currentSet after move.");
-  is(otherNavbar.getAttribute("currentset"), navbarCurrentset,
-     "Should have updated other window's currentSet after move.");
-
-  CustomizableUI.addWidgetToArea("home-button", CustomizableUI.AREA_BOOKMARKS);
-  navbarCurrentset = navbarCurrentset.replace("home-button,", "");
-  personalbarCurrentset = personalbarCurrentset + ",home-button";
-  is(navbar.getAttribute("currentset"), navbarCurrentset,
-     "Should have updated navbar currentSet after implied remove.");
-  is(otherNavbar.getAttribute("currentset"), navbarCurrentset,
-     "Should have updated other window's navbar currentSet after implied remove.");
-  is(personalbar.getAttribute("currentset"), personalbarCurrentset,
-     "Should have updated personalbar currentSet after add.");
-  is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset,
-     "Should have updated other window's personalbar currentSet after add.");
-
-  CustomizableUI.removeWidgetFromArea("home-button");
-  personalbarCurrentset = personalbarCurrentset.replace(",home-button", "");
-  is(personalbar.getAttribute("currentset"), personalbarCurrentset,
-     "Should have updated currentSet after remove.");
-  is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset,
-     "Should have updated other window's currentSet after remove.");
-
-  await promiseWindowClosed(otherWin);
-  // Reset in asyncCleanup will put our button back for us.
-});
-
-add_task(async function asyncCleanup() {
-  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
-  setToolbarVisibility(personalbar, false);
-  await resetCustomization();
-});
--- a/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js
+++ b/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js
@@ -5,34 +5,34 @@
 "use strict";
 
 const kLazyAreaId = "test-890262-lazy-area";
 const kWidget1Id  = "test-890262-widget1";
 const kWidget2Id  = "test-890262-widget2";
 
 setupArea();
 
-// Destroying a widget after defaulting it to a non-legacy area should work.
+// Destroying a widget after defaulting it to a lazy area should work.
 add_task(function() {
   CustomizableUI.createWidget({
     id: kWidget1Id,
     removable: true,
     defaultArea: kLazyAreaId,
   });
   let noError = true;
   try {
     CustomizableUI.destroyWidget(kWidget1Id);
   } catch (ex) {
     Cu.reportError(ex);
     noError = false;
   }
   ok(noError, "Shouldn't throw an exception for a widget that was created in a not-yet-constructed area");
 });
 
-// Destroying a widget after moving it to a non-legacy area should work.
+// Destroying a widget after moving it to a lazy area should work.
 add_task(function() {
   CustomizableUI.createWidget({
     id: kWidget2Id,
     removable: true,
     defaultArea: CustomizableUI.AREA_NAVBAR,
   });
 
   CustomizableUI.addWidgetToArea(kWidget2Id, kLazyAreaId);
--- a/browser/components/customizableui/test/browser_913972_currentset_overflow.js
+++ b/browser/components/customizableui/test/browser_913972_currentset_overflow.js
@@ -1,55 +1,50 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
 
-// Resize to a small window, resize back, shouldn't affect currentSet
+registerCleanupFunction(async function asyncCleanup() {
+  await resetCustomization();
+});
+
+// Resize to a small window, resize back, shouldn't affect default state.
 add_task(async function() {
   let originalWindowWidth = window.outerWidth;
-  let oldCurrentSet = navbar.currentSet;
   ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
   ok(CustomizableUI.inDefaultState, "Should start in default state.");
   let oldChildCount = navbar.customizationTarget.childElementCount;
   window.resizeTo(kForceOverflowWidthPx, window.outerHeight);
   await waitForCondition(() => navbar.hasAttribute("overflowing"));
   ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
-  is(navbar.currentSet, oldCurrentSet, "Currentset should be the same when overflowing.");
   ok(CustomizableUI.inDefaultState, "Should still be in default state when overflowing.");
   ok(navbar.customizationTarget.childElementCount < oldChildCount, "Should have fewer children.");
   window.resizeTo(originalWindowWidth, window.outerHeight);
   await waitForCondition(() => !navbar.hasAttribute("overflowing"));
   ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
-  is(navbar.currentSet, oldCurrentSet, "Currentset should still be the same now we're no longer overflowing.");
   ok(CustomizableUI.inDefaultState, "Should still be in default state now we're no longer overflowing.");
 
   // Verify actual physical placements match those of the placement array:
   let placementCounter = 0;
   let placements = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR);
   for (let node of navbar.customizationTarget.children) {
     if (node.getAttribute("skipintoolbarset") == "true") {
       continue;
     }
     is(placements[placementCounter++], node.id, "Nodes should match after overflow");
   }
   is(placements.length, placementCounter, "Should have as many nodes as expected");
   is(navbar.customizationTarget.childElementCount, oldChildCount, "Number of nodes should match");
 });
 
-// Enter and exit customization mode, check that currentSet works
+// Enter and exit customization mode, check that default state is correct.
 add_task(async function() {
-  let oldCurrentSet = navbar.currentSet;
   ok(CustomizableUI.inDefaultState, "Should start in default state.");
   await startCustomizing();
   ok(CustomizableUI.inDefaultState, "Should be in default state in customization mode.");
-  is(navbar.currentSet, oldCurrentSet, "Currentset should be the same in customization mode.");
   await endCustomizing();
   ok(CustomizableUI.inDefaultState, "Should be in default state after customization mode.");
-  is(navbar.currentSet, oldCurrentSet, "Currentset should be the same after customization mode.");
 });
 
-add_task(async function asyncCleanup() {
-  await resetCustomization();
-});
--- a/browser/components/customizableui/test/browser_940013_registerToolbarNode_calls_registerArea.js
+++ b/browser/components/customizableui/test/browser_940013_registerToolbarNode_calls_registerArea.js
@@ -3,37 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kToolbarId = "test-registerToolbarNode-toolbar";
 const kButtonId = "test-registerToolbarNode-button";
 registerCleanupFunction(cleanup);
 
-// Registering a toolbar with defaultset attribute should work
-add_task(async function() {
-  ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
-  let btn = createDummyXULButton(kButtonId);
-  let toolbar = document.createXULElement("toolbar");
-  toolbar.id = kToolbarId;
-  toolbar.setAttribute("customizable", true);
-  toolbar.setAttribute("defaultset", kButtonId);
-  gNavToolbox.appendChild(toolbar);
-  ok(CustomizableUI.areas.includes(kToolbarId),
-     "Toolbar should have been registered automatically.");
-  is(CustomizableUI.getAreaType(kToolbarId), CustomizableUI.TYPE_TOOLBAR,
-     "Area should be registered as toolbar");
-  assertAreaPlacements(kToolbarId, [kButtonId]);
-  ok(!CustomizableUI.inDefaultState, "No longer in default state after toolbar is registered and visible.");
-  CustomizableUI.unregisterArea(kToolbarId, true);
-  toolbar.remove();
-  ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
-  btn.remove();
-});
-
 // Registering a toolbar without a defaultset attribute should
 // wait for the registerArea call
 add_task(async function() {
   ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
   let btn = createDummyXULButton(kButtonId);
   let toolbar = document.createXULElement("toolbar");
   toolbar.id = kToolbarId;
   toolbar.setAttribute("customizable", true);
--- a/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
+++ b/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
@@ -43,17 +43,17 @@ add_task(async function() {
 
   setToolbarVisibility(toolbar, true);
 
   info("Check that removing the area registration from within customize mode works");
   CustomizableUI.unregisterArea(TOOLBARID);
   ok(CustomizableUI.inDefaultState, "Now that the toolbar is no longer registered, should be in default state.");
   ok(!gCustomizeMode.areas.has(toolbar), "Toolbar shouldn't be known to customize mode.");
 
-  CustomizableUI.registerArea(TOOLBARID, {legacy: true, defaultPlacements: []});
+  CustomizableUI.registerArea(TOOLBARID, {defaultPlacements: []});
   CustomizableUI.registerToolbarNode(toolbar, []);
   ok(!CustomizableUI.inDefaultState, "Now that the toolbar is registered again, should no longer be in default state.");
   ok(gCustomizeMode.areas.has(toolbar), "Toolbar should be known to customize mode again.");
 
   button.scrollIntoView();
   simulateItemDrag(button, toolbar);
   ok(CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId), "Button moved out of palette");
   is(CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId).area, TOOLBARID, "Button's back on toolbar");
--- a/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
+++ b/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
@@ -85,28 +85,16 @@ add_task(function() {
   }
   ok(!exceptionThrown, "Changing defaultPlacements shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
   CustomizableUI.unregisterArea("area-996899-2", true);
 });
 
 add_task(function() {
   let exceptionThrown;
   try {
-    CustomizableUI.registerArea("area-996899-3", { legacy: true });
-    CustomizableUI.registerArea("area-996899-3", { legacy: false });
-  } catch (ex) {
-    exceptionThrown = ex;
-  }
-  ok(exceptionThrown, "Changing 'legacy' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
-  CustomizableUI.unregisterArea("area-996899-3", true);
-});
-
-add_task(function() {
-  let exceptionThrown;
-  try {
     CustomizableUI.registerArea("area-996899-4", { overflowable: true });
     CustomizableUI.registerArea("area-996899-4", { overflowable: false });
   } catch (ex) {
     exceptionThrown = ex;
   }
   ok(exceptionThrown, "Changing 'overflowable' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
   CustomizableUI.unregisterArea("area-996899-4", true);
 });
--- a/browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js
+++ b/browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js
@@ -4,78 +4,71 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 const kTestBarID = "testBar";
 const kWidgetID = "characterencoding-button";
 
-function createTestBar(aLegacy) {
+function createTestBar() {
   let testBar = document.createXULElement("toolbar");
   testBar.id = kTestBarID;
   testBar.setAttribute("customizable", "true");
   CustomizableUI.registerArea(kTestBarID, {
     type: CustomizableUI.TYPE_TOOLBAR,
-    legacy: aLegacy,
   });
   gNavToolbox.appendChild(testBar);
   return testBar;
 }
 
 /**
  * Helper function that does the following:
  *
  * 1) Creates a custom toolbar and registers it
- *    with CustomizableUI. Sets the legacy attribute
- *    of the object passed to registerArea to aLegacy.
+ *    with CustomizableUI.
  * 2) Adds the widget with ID aWidgetID to that new
  *    toolbar.
  * 3) Enters customize mode and makes sure that the
  *    widget is still in the right toolbar.
  * 4) Exits customize mode, then removes and deregisters
  *    the custom toolbar.
  * 5) Checks that the widget has no placement.
  * 6) Re-adds and re-registers a custom toolbar with the same
  *    ID and options as the first one.
  * 7) Enters customize mode and checks that the widget is
  *    properly back in the toolbar.
  * 8) Exits customize mode, removes and de-registers the
  *    toolbar, and resets the toolbars to default.
  */
-function checkRestoredPresence(aWidgetID, aLegacy) {
+function checkRestoredPresence(aWidgetID) {
   return (async function() {
-    let testBar = createTestBar(aLegacy);
+    let testBar = createTestBar();
     CustomizableUI.addWidgetToArea(aWidgetID, kTestBarID);
     let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
     is(placement.area, kTestBarID,
        "Expected " + aWidgetID + " to be in the test toolbar");
 
     CustomizableUI.unregisterArea(testBar.id);
     testBar.remove();
 
     placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
     is(placement, null, "Expected " + aWidgetID + " to be in the palette");
 
-    testBar = createTestBar(aLegacy);
+    testBar = createTestBar();
 
     await startCustomizing();
     placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
     is(placement.area, kTestBarID,
        "Expected " + aWidgetID + " to be in the test toolbar");
     await endCustomizing();
 
     CustomizableUI.unregisterArea(testBar.id);
     testBar.remove();
 
     await resetCustomization();
   })();
 }
 
 add_task(async function() {
-  await checkRestoredPresence("downloads-button", false);
-  await checkRestoredPresence("downloads-button", true);
+  await checkRestoredPresence("downloads-button");
+  await checkRestoredPresence("characterencoding-button");
 });
-
-add_task(async function() {
-  await checkRestoredPresence("characterencoding-button", false);
-  await checkRestoredPresence("characterencoding-button", true);
-});
--- a/browser/components/customizableui/test/browser_currentset_post_reset.js
+++ b/browser/components/customizableui/test/browser_currentset_post_reset.js
@@ -1,23 +1,24 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 function checkSpacers() {
+  let bsPass = ChromeUtils.import("resource:///modules/CustomizableUI.jsm", {});
   let navbarWidgets = CustomizableUI.getWidgetIdsInArea("nav-bar");
-  let currentSetWidgets = document.getElementById("nav-bar").currentSet.split(",");
+  let currentSetWidgets = bsPass.CustomizableUIInternal._getCurrentWidgetsInContainer(document.getElementById("nav-bar"));
   navbarWidgets = navbarWidgets.filter(w => CustomizableUI.isSpecialWidget(w));
   currentSetWidgets = currentSetWidgets.filter(w => CustomizableUI.isSpecialWidget(w));
   Assert.deepEqual(navbarWidgets, currentSetWidgets, "Should have the same 'special' widgets in currentset and placements");
 }
 
 /**
- * Check that after a reset, the currentset property correctly deals with flexible spacers.
+ * Check that after a reset, CUI's internal bookkeeping correctly deals with flexible spacers.
  */
 add_task(async function() {
   await startCustomizing();
   checkSpacers();
 
   CustomizableUI.addWidgetToArea("spring", "nav-bar", 4 /* Insert before the last extant spacer */);
   await gCustomizeMode.reset();
   checkSpacers();
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2182,17 +2182,17 @@ BrowserGlue.prototype = {
       }
     }
   },
 
   // eslint-disable-next-line complexity
   _migrateUI: function BG__migrateUI() {
     // Use an increasing number to keep track of the current migration state.
     // Completely unrelated to the current Firefox release number.
-    const UI_VERSION = 76;
+    const UI_VERSION = 77;
     const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
 
     let currentUIVersion;
     if (Services.prefs.prefHasUserValue("browser.migration.version")) {
       currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
     } else {
       // This is a new profile, nothing to migrate.
       Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
@@ -2543,16 +2543,24 @@ BrowserGlue.prototype = {
       if (onboardingPrefs) {
         let onboardingPrefsArray = onboardingPrefs.getChildList("");
         for (let item of onboardingPrefsArray) {
           Services.prefs.clearUserPref("browser.onboarding." + item);
         }
       }
     }
 
+    if (currentUIVersion < 77) {
+      // Remove currentset from all the toolbars
+      let toolbars = ["nav-bar", "PersonalToolbar", "TabsToolbar", "toolbar-menubar"];
+      for (let toolbarId of toolbars) {
+        xulStore.removeValue(BROWSER_DOCURL, toolbarId, "currentset");
+      }
+    }
+
     // Update the migration version.
     Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
   },
 
   _checkForDefaultBrowser() {
     // Perform default browser checking.
     if (!ShellService) {
       return;