merge mozilla-central to mozilla-beta. a=merge l10n=its-still-central-really CLOSED TREE
authorSebastian Hengst <archaeopteryx@coole-files.de>
Mon, 30 Apr 2018 18:27:24 +0300
changeset 472340 1b1a8ab75f1fa8b6bc7ebba65909dc87aa53ad7b
parent 472146 b5ac348daeec346d4bfb38aa01fadb7354fd156a (current diff)
parent 472339 63519bfd42ee379f597c0357af2e712ec3cd9f50 (diff)
child 472341 54735fb44eeff8b04a592a14d3c506370ffc2f76
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0
merge mozilla-central to mozilla-beta. a=merge l10n=its-still-central-really CLOSED TREE
dom/webidl/PopupBoxObject.webidl
layout/reftests/svg/transform-01.svg
layout/style/nsCSSPropAliasList.h
layout/style/nsCSSPropList.h
layout/xul/PopupBoxObject.cpp
layout/xul/PopupBoxObject.h
layout/xul/crashtests/434458-1.xul
testing/mozbase/mozinstall/tests/Installer-Stubs/firefox.dmg
testing/mozbase/mozinstall/tests/Installer-Stubs/firefox.tar.bz2
testing/mozbase/mozinstall/tests/Installer-Stubs/firefox.zip
testing/mozbase/mozinstall/tests/test.py
testing/raptor/raptor/tests/raptor-chrome-tp7.ini
testing/raptor/raptor/tests/raptor-speedometer.ini
testing/web-platform/meta/css/CSS2/floats-clear/clear-on-parent-with-margins-no-clearance.html.ini
testing/web-platform/meta/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html.ini
testing/web-platform/meta/webdriver/tests/element_click/bubbling.py.ini
testing/web-platform/meta/webdriver/tests/execute_script/cyclic.py.ini
testing/web-platform/tests/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html
testing/web-platform/tests/webaudio/the-audio-api/the-delaynode-interface/idl-test.html
testing/web-platform/tests/webaudio/the-audio-api/the-gainnode-interface/idl-test.html
--- a/accessible/jsat/ContentControl.jsm
+++ b/accessible/jsat/ContentControl.jsm
@@ -497,12 +497,12 @@ this.ContentControl.prototype = {
     }
   },
 
   cancelAutoMove: function cc_cancelAutoMove() {
     this.window.clearTimeout(this._autoMove);
     this._autoMove = 0;
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
+  QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference,
     Ci.nsIMessageListener
   ])
 };
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -551,20 +551,17 @@ this.EventManager.prototype = {
     }
   },
 
   onLocationChange: function onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
     let docAcc = Utils.AccService.getAccessibleFor(aWebProgress.DOMWindow.document);
     this.present(Presentation.tabStateChanged(docAcc, "newdoc"));
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsISupports,
-                                         Ci.nsIObserver])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference, Ci.nsIObserver])
 };
 
 const AccessibilityEventObserver = {
 
   /**
    * A WeakMap containing [content, EventManager] pairs.
    */
   eventManagers: new WeakMap(),
--- a/accessible/jsat/Traversal.jsm
+++ b/accessible/jsat/Traversal.jsm
@@ -62,17 +62,17 @@ BaseTraversalRule.prototype = {
         if (control && this._explicitMatchRoles.has(control.role)) {
           matchResult = this._matchFunc(control) | Filters.IGNORE_SUBTREE;
         }
       }
 
       return matchResult;
     },
 
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessibleTraversalRule])
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIAccessibleTraversalRule])
 };
 
 var gSimpleTraversalRoles =
   [Roles.MENUITEM,
    Roles.LINK,
    Roles.PAGETAB,
    Roles.GRAPHIC,
    Roles.STATICTEXT,
--- a/accessible/jsat/Utils.jsm
+++ b/accessible/jsat/Utils.jsm
@@ -1052,11 +1052,11 @@ PrefCache.prototype = {
       try {
         this.callback(this.name, this.value, false);
       } catch (x) {
         Logger.logException(x);
       }
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                          Ci.nsISupportsWeakReference])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                           Ci.nsISupportsWeakReference])
 };
--- a/accessible/tests/mochitest/events/docload/test_docload_root.html
+++ b/accessible/tests/mochitest/events/docload/test_docload_root.html
@@ -70,16 +70,19 @@
             {
               role: ROLE_CHROME_WINDOW
             },
             {
               role: ROLE_CHROME_WINDOW
             },
             {
               role: ROLE_CHROME_WINDOW
+            },
+            {
+              role: ROLE_CHROME_WINDOW
             }
           ]
         };
 
         testAccessibleTree(gRootAcc, accTree);
 
         gDialogDoc = gDialog.document;
         ok(isAccessibleInCache(gDialogDoc),
--- a/accessible/tests/mochitest/events/docload/test_docload_shutdown.html
+++ b/accessible/tests/mochitest/events/docload/test_docload_shutdown.html
@@ -86,16 +86,19 @@
             {
               role: ROLE_CHROME_WINDOW
             },
             {
               role: ROLE_CHROME_WINDOW
             },
             {
               role: ROLE_CHROME_WINDOW
+            },
+            {
+              role: ROLE_CHROME_WINDOW
             }
           ]
         };
 
         testAccessibleTree(gRootAcc, accTree);
         // After timeout after event hide for iframe was handled the document
         // accessible for iframe's document should no longer be in cache.
         ok(!isAccessibleInCache(gIframeDoc),
--- a/accessible/tests/mochitest/pivot.js
+++ b/accessible/tests/mochitest/pivot.js
@@ -29,17 +29,17 @@ var HeadersTraversalRule =
   },
 
   preFilter: PREFILTER_INVISIBLE,
 
   match(aAccessible) {
     return FILTER_MATCH;
   },
 
-  QueryInterface: XPCOMUtils.generateQI([nsIAccessibleTraversalRule])
+  QueryInterface: ChromeUtils.generateQI([nsIAccessibleTraversalRule])
 };
 
 /**
  * Traversal rule for all focusable nodes or leafs.
  */
 var ObjectTraversalRule =
 {
   getMatchRoles(aRules) {
@@ -57,17 +57,17 @@ var ObjectTraversalRule =
       rv = FILTER_IGNORE_SUBTREE | FILTER_MATCH;
     else if (aAccessible.childCount == 0 &&
              role != ROLE_STATICTEXT && aAccessible.name.trim())
       rv = FILTER_MATCH;
 
     return rv;
   },
 
-  QueryInterface: XPCOMUtils.generateQI([nsIAccessibleTraversalRule])
+  QueryInterface: ChromeUtils.generateQI([nsIAccessibleTraversalRule])
 };
 
 // //////////////////////////////////////////////////////////////////////////////
 // Virtual state invokers and checkers
 
 /**
  * A checker for virtual cursor changed events.
  */
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1724,15 +1724,15 @@ pref("browser.chrome.errorReporter.infoU
      "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/nightly-error-collection");
 
 // Normandy client preferences
 pref("app.normandy.api_url", "https://normandy.cdn.mozilla.net/api/v1");
 pref("app.normandy.dev_mode", false);
 pref("app.normandy.enabled", true);
 pref("app.normandy.first_run", true);
 pref("app.normandy.logging.level", 50); // Warn
-pref("app.normandy.run_interval_seconds", 86400); // 24 hours
+pref("app.normandy.run_interval_seconds", 21600); // 6 hours
 pref("app.normandy.shieldLearnMoreUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/shield");
 #ifdef MOZ_DATA_REPORTING
 pref("app.shield.optoutstudies.enabled", true);
 #else
 pref("app.shield.optoutstudies.enabled", false);
 #endif
--- a/browser/base/content/aboutDialog-appUpdater.js
+++ b/browser/base/content/aboutDialog-appUpdater.js
@@ -296,22 +296,17 @@ appUpdater.prototype =
       // notified with the normal app update user interface so this is safe.
       gAppUpdater.isChecking = false;
       gAppUpdater.selectPanel("noUpdatesFound");
     },
 
     /**
      * See nsISupports.idl
      */
-    QueryInterface(aIID) {
-      if (!aIID.equals(Ci.nsIUpdateCheckListener) &&
-          !aIID.equals(Ci.nsISupports))
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      return this;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIUpdateCheckListener"]),
   },
 
   /**
    * Starts the download of an update mar.
    */
   startDownload() {
     if (!this.update)
       this.update = this.um.activeUpdate;
@@ -422,16 +417,10 @@ appUpdater.prototype =
   onProgress(aRequest, aContext, aProgress, aProgressMax) {
     this.downloadStatus.textContent =
       DownloadUtils.getTransferTotal(aProgress, aProgressMax);
   },
 
   /**
    * See nsISupports.idl
    */
-  QueryInterface(aIID) {
-    if (!aIID.equals(Ci.nsIProgressEventSink) &&
-        !aIID.equals(Ci.nsIRequestObserver) &&
-        !aIID.equals(Ci.nsISupports))
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    return this;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIProgressEventSink", "nsIRequestObserver"]),
 };
--- a/browser/base/content/browser-data-submission-info-bar.js
+++ b/browser/base/content/browser-data-submission-info-bar.js
@@ -113,13 +113,13 @@ var gDataNotificationInfoBar = {
         this._actionTaken = true;
         this._clearPolicyNotification();
         break;
 
       default:
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference,
   ]),
 };
--- a/browser/base/content/browser-feeds.js
+++ b/browser/base/content/browser-feeds.js
@@ -407,18 +407,18 @@ var FeedHandler = {
                 .createInstance(Ci.nsIProcess);
       p.init(clientApp);
       p.run(false, [aSpec], 1);
     }
   },
 
   // nsISupports
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 
 
   init() {
     window.messageManager.addMessageListener("FeedWriter:ChooseClientApp", this);
     window.messageManager.addMessageListener("FeedWriter:GetSubscriptionUI", this);
     window.messageManager.addMessageListener("FeedWriter:SetFeedPrefsAndSubscribe", this);
     window.messageManager.addMessageListener("FeedWriter:ShownFirstRun", this);
 
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -34,20 +34,17 @@ var FullZoom = {
         !Services.prefs.getBoolPref("privacy.resistFingerprinting") &&
         Services.prefs.getBoolPref("browser.zoom.siteSpecific");
     }
     return this._siteSpecificPref;
   },
 
   // nsISupports
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsIContentPrefObserver,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsISupports]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver, Ci.nsIContentPrefObserver, Ci.nsISupportsWeakReference]),
 
   // Initialization & Destruction
 
   init: function FullZoom_init() {
     gBrowser.addEventListener("ZoomChangeUsingMouseWheel", this);
 
     // Register ourselves with the service so we know when our pref changes.
     this._cps2 = Cc["@mozilla.org/content-pref/service;1"].
@@ -203,20 +200,31 @@ var FullZoom = {
     // to the new location.
     this._ignorePendingZoomAccesses(browser);
 
     if (!aURI || (aIsTabSwitch && !this.siteSpecific)) {
       this._notifyOnLocationChange(browser);
       return;
     }
 
-    // Avoid the cps roundtrip and apply the default/global pref.
     if (aURI.spec == "about:blank") {
-      this._applyPrefToZoom(undefined, browser,
-                            this._notifyOnLocationChange.bind(this, browser));
+      if (!browser.contentPrincipal || browser.contentPrincipal.isNullPrincipal) {
+        // For an about:blank with a null principal, zooming any amount does not
+        // make any sense - so simply do 100%.
+        this._applyPrefToZoom(1, browser,
+                              this._notifyOnLocationChange.bind(this, browser));
+      } else {
+        // If it's not a null principal, there may be content loaded into it,
+        // so use the global pref. This will avoid a cps2 roundtrip if we've
+        // already loaded the global pref once. Really, this should probably
+        // use the contentPrincipal's origin if it's an http(s) principal.
+        // (See bug 1457597)
+        this._applyPrefToZoom(undefined, browser,
+                              this._notifyOnLocationChange.bind(this, browser));
+      }
       return;
     }
 
     // Media documents should always start at 1, and are not affected by prefs.
     if (!aIsTabSwitch && browser.isSyntheticDocument) {
       ZoomManager.setZoomForBrowser(browser, 1);
       // _ignorePendingZoomAccesses already called above, so no need here.
       this._notifyOnLocationChange(browser);
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -91,25 +91,23 @@
                           accesskey="&goOfflineCmd.accesskey;"
                           type="checkbox"
                           observes="workOfflineMenuitemState"
                           oncommand="BrowserOffline.toggleOfflineStatus();"/>
                 <menuitem id="menu_FileQuitItem"
 #ifdef XP_WIN
                           label="&quitApplicationCmdWin2.label;"
                           accesskey="&quitApplicationCmdWin2.accesskey;"
-#else
-#ifdef XP_MACOSX
+#elifdef XP_MACOSX
                           label="&quitApplicationCmdMac2.label;"
 #else
                           label="&quitApplicationCmd.label;"
                           accesskey="&quitApplicationCmd.accesskey;"
 #endif
                           key="key_quitApplication"
-#endif
                           command="cmd_quitApplication"/>
               </menupopup>
             </menu>
 
             <menu id="edit-menu" label="&editMenu.label;"
                   accesskey="&editMenu.accesskey;">
               <menupopup id="menu_EditPopup"
                          onpopupshowing="updateEditUIVisibility()"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -902,17 +902,17 @@ var PlacesMenuDNDHandler = {
     let popup = event.target.lastChild;
     if (this._loadTimer || popup.state === "showing" || popup.state === "open")
       return;
 
     this._loadTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     this._loadTimer.initWithCallback(() => {
       this._loadTimer = null;
       popup.setAttribute("autoopened", "true");
-      popup.showPopup(popup);
+      popup.openPopup();
     }, this._springLoadDelayMs, Ci.nsITimer.TYPE_ONE_SHOT);
     event.preventDefault();
     event.stopPropagation();
   },
 
   /**
    * Handles dragleave on the <menu> element.
    */
@@ -1744,17 +1744,17 @@ var BookmarkingUI = {
     if (aNode.id != this.BOOKMARK_BUTTON_ID || win != window)
       return;
 
     // The view gets broken by being removed and reinserted. Uninit
     // here so popupshowing will generate a new one:
     this._uninitView();
   },
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsINavBookmarkObserver
   ])
 };
 
 var AutoShowBookmarksToolbar = {
   init() {
     Services.obs.addObserver(this, "autoshow-bookmarks-toolbar");
   },
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -91,21 +91,18 @@ var gPluginHandler = {
 
   // Callback for user clicking on a disabled plugin
   managePlugins() {
     BrowserOpenAddonsMgr("addons://list/plugin");
   },
 
   // Callback for user clicking on the link in a click-to-play plugin
   // (where the plugin has an update)
-  openPluginUpdatePage(pluginTag) {
-    let url = Blocklist.getPluginInfoURL(pluginTag);
-    if (!url) {
-      url = Blocklist.getPluginBlocklistURL(pluginTag);
-    }
+  async openPluginUpdatePage(pluginTag) {
+    let url = await Blocklist.getPluginBlockURL(pluginTag);
     openTrustedLinkIn(url, "tab");
   },
 
   submitReport: function submitReport(runID, keyVals, submitURLOptIn) {
     if (!AppConstants.MOZ_CRASHREPORTER) {
       return;
     }
     Services.prefs.setBoolPref("dom.ipc.plugins.reportCrashURL", submitURLOptIn);
@@ -266,30 +263,16 @@ var gPluginHandler = {
     } else {
       pluginData = new Map();
     }
 
     for (let pluginInfo of plugins) {
       if (pluginData.has(pluginInfo.permissionString)) {
         continue;
       }
-
-      // If a block contains an infoURL, we should always prefer that to the default
-      // URL that we construct in-product, even for other blocklist types.
-      let url = Blocklist.getPluginInfoURL(pluginInfo.pluginTag);
-
-      if (pluginInfo.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
-        if (!url) {
-          url = Blocklist.getPluginBlocklistURL(pluginInfo.pluginTag);
-        }
-      } else {
-        url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "clicktoplay";
-      }
-      pluginInfo.detailsLink = url;
-
       pluginData.set(pluginInfo.permissionString, pluginInfo);
     }
 
     let primaryPluginPermission = null;
     if (showNow) {
       primaryPluginPermission = plugins[0].permissionString;
     }
 
@@ -301,29 +284,16 @@ var gPluginHandler = {
         notification.reshow();
         browser.messageManager.sendAsyncMessage("BrowserPlugins:NotificationShown");
       }
       return;
     }
 
     if (plugins.length == 1) {
       let pluginInfo = plugins[0];
-      // If a block contains an infoURL, we should always prefer that to the default
-      // URL that we construct in-product, even for other blocklist types.
-      let url = Blocklist.getPluginInfoURL(pluginInfo.pluginTag);
-
-      if (pluginInfo.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
-        if (!url) {
-          url = Blocklist.getPluginBlocklistURL(pluginInfo.pluginTag);
-        }
-      } else {
-        url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "clicktoplay";
-      }
-      pluginInfo.detailsLink = url;
-
       let chromeWin = window.QueryInterface(Ci.nsIDOMChromeWindow);
       let isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(chromeWin);
 
       let active = pluginInfo.fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE;
 
       let options = {
         dismissed: !showNow,
         hideClose: !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"),
--- a/browser/base/content/browser-sync.js
+++ b/browser/base/content/browser-sync.js
@@ -685,13 +685,13 @@ var gSync = {
 
   onSyncDisabled() {
     const toHide = [...document.querySelectorAll(".sync-ui-item")];
     for (const item of toHide) {
       item.hidden = true;
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
   ])
 };
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4595,25 +4595,20 @@ var XULBrowserWindow = {
   // Stored Status, Link and Loading values
   status: "",
   defaultStatus: "",
   overLink: "",
   startTime: 0,
   isBusy: false,
   busyUI: false,
 
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIWebProgressListener) ||
-        aIID.equals(Ci.nsIWebProgressListener2) ||
-        aIID.equals(Ci.nsISupportsWeakReference) ||
-        aIID.equals(Ci.nsIXULBrowserWindow) ||
-        aIID.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_NOINTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
+                                          "nsIWebProgressListener2",
+                                          "nsISupportsWeakReference",
+                                          "nsIXULBrowserWindow"]),
 
   get stopCommand() {
     delete this.stopCommand;
     return this.stopCommand = document.getElementById("Browser:Stop");
   },
   get reloadCommand() {
     delete this.reloadCommand;
     return this.reloadCommand = document.getElementById("Browser:Reload");
@@ -5379,17 +5374,17 @@ var TabsProgressListener = {
 
     FullZoom.onLocationChange(aLocationURI, false, aBrowser);
   },
 };
 
 function nsBrowserAccess() { }
 
 nsBrowserAccess.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIBrowserDOMWindow]),
 
   _openURIInNewTab(aURI, aReferrer, aReferrerPolicy, aIsPrivate,
                    aIsExternal, aForceNotRemote = false,
                    aUserContextId = Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID,
                    aOpenerWindow = null, aOpenerBrowser = null,
                    aTriggeringPrincipal = null, aNextTabParentId = 0, aName = "") {
     let win, needToFocusWin;
 
@@ -7735,18 +7730,18 @@ var RestoreLastSessionObserver = {
 
   observe() {
     // The last session can only be restored once so there's
     // no way we need to re-enable our menu item.
     Services.obs.removeObserver(this, "sessionstore-last-session-cleared");
     goSetCommandEnabled("Browser:RestoreLastSession", false);
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference])
 };
 
 function restoreLastSession() {
   SessionStore.restoreLastSession();
 }
 
 /* Observes menus and adjusts their size for better
  * usability when opened via a touch screen. */
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -1519,14 +1519,14 @@ let OfflineApps = {
     if (aTopic == "offline-cache-update-completed") {
       let cacheUpdate = aSubject.QueryInterface(Ci.nsIOfflineCacheUpdate);
       let uri = cacheUpdate.manifestURI;
       if (uri && this._docManifestSet.has(uri.spec)) {
         sendAsyncMessage("OfflineApps:CheckUsage", {uri: uri.spec});
       }
     }
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 };
 
 addEventListener("MozApplicationManifest", OfflineApps, false);
 addMessageListener("OfflineApps:StartFetching", OfflineApps);
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -854,20 +854,17 @@ var RefreshBlocker = {
                           .QueryInterface(Ci.nsIRefreshURI);
 
       let URI = Services.io.newURI(data.URI);
 
       refreshURI.forceRefreshURI(URI, null, data.delay, true);
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener2,
-                                         Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsISupports]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener2, Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
 };
 
 RefreshBlocker.init();
 
 var UserContextIdNotifier = {
   init() {
     addEventListener("DOMWindowCreated", this);
   },
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -4569,26 +4569,21 @@ class TabProgressListener {
     this._callProgressListeners("onSecurityChange",
                                 [aWebProgress, aRequest, aState]);
   }
 
   onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
     return this._callProgressListeners("onRefreshAttempted",
                                        [aWebProgress, aURI, aDelay, aSameURI]);
   }
-
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIWebProgressListener) ||
-        aIID.equals(Ci.nsIWebProgressListener2) ||
-        aIID.equals(Ci.nsISupportsWeakReference) ||
-        aIID.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_NOINTERFACE;
-  }
 }
+TabProgressListener.prototype.QueryInterface = ChromeUtils.generateQI(
+  ["nsIWebProgressListener",
+   "nsIWebProgressListener2",
+   "nsISupportsWeakReference"]);
 
 var StatusPanel = {
   get panel() {
     window.addEventListener("resize", this);
 
     delete this.panel;
     return this.panel = document.getElementById("statuspanel");
   },
--- a/browser/base/content/test/about/head.js
+++ b/browser/base/content/test/about/head.js
@@ -114,17 +114,17 @@ function waitForDocLoadAndStopIt(aExpect
           wp.removeProgressListener(progressListener);
 
           let chan = req.QueryInterface(Ci.nsIChannel);
           dump(`waitForDocLoadAndStopIt: Document start: ${chan.URI.spec}\n`);
 
           stopContent(contentStopFromProgressListener, chan.originalURI.spec);
         }
       },
-      QueryInterface: XPCOMUtils.generateQI(["nsISupportsWeakReference"])
+      QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"])
     };
     wp.addProgressListener(progressListener, wp.NOTIFY_STATE_WINDOW);
 
     /**
      * As |this| is undefined and we can't extend |docShell|, adding an unload
      * event handler is the easiest way to ensure the weakly referenced
      * progress listener is kept alive as long as necessary.
      */
--- a/browser/base/content/test/chrome/test_aboutCrashed.xul
+++ b/browser/base/content/test/chrome/test_aboutCrashed.xul
@@ -27,18 +27,18 @@
                             .getInterface(Ci.nsIWebProgress)
                             .removeProgressListener(progressListener,
                                                     Ci.nsIWebProgress.NOTIFY_LOCATION);
 
               resolve();
             }
           },
 
-          QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                                 Ci.nsISupportsWeakReference])
+          QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                                  Ci.nsISupportsWeakReference])
         };
 
         frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIWebProgress)
                       .addProgressListener(progressListener,
                                            Ci.nsIWebProgress.NOTIFY_LOCATION);
       });
     }
--- a/browser/base/content/test/general/browser_bug356571.js
+++ b/browser/base/content/test/general/browser_bug356571.js
@@ -17,17 +17,17 @@ var fakePromptServiceFactory = {
   createInstance(aOuter, aIid) {
     if (aOuter != null)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return promptService.QueryInterface(aIid);
   }
 };
 
 var promptService = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPromptService]),
   alert() {
     didFail = true;
   }
 };
 
 /* FIXME
 Cm.QueryInterface(Ci.nsIComponentRegistrar)
   .registerFactory(Components.ID(kPromptServiceUUID), "Prompt Service",
--- a/browser/base/content/test/general/browser_e10s_about_process.js
+++ b/browser/base/content/test/general/browser_e10s_about_process.js
@@ -41,31 +41,31 @@ AboutModule.prototype = {
     ok(false, "Called getURIFlags for an unknown page " + aURI.spec);
     return 0;
   },
 
   getIndexedDBOriginPostfix(aURI) {
     return null;
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIAboutModule])
 };
 
 var AboutModuleFactory = {
   createInstance(aOuter, aIID) {
     if (aOuter)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return new AboutModule().QueryInterface(aIID);
   },
 
   lockFactory(aLock) {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIFactory])
 };
 
 add_task(async function init() {
   let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
   for (let module of TEST_MODULES) {
     registrar.registerFactory(Components.ID(module.id), "",
                               "@mozilla.org/network/protocol/about;1?what=" + module.path,
                               AboutModuleFactory);
--- a/browser/base/content/test/general/browser_fullscreen-window-open.js
+++ b/browser/base/content/test/general/browser_fullscreen-window-open.js
@@ -337,11 +337,10 @@ WindowListener.prototype = {
       } else {
         domwindow.close();
         executeSoon(this.callBack_onFinalize);
       }
     };
     domwindow.addEventListener("load", onLoad, true);
   },
   onCloseWindow(aXULWindow) {},
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediatorListener,
-                                         Ci.nsISupports]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWindowMediatorListener]),
 };
--- a/browser/base/content/test/general/browser_homeDrop.js
+++ b/browser/base/content/test/general/browser_homeDrop.js
@@ -24,17 +24,17 @@ add_task(async function() {
     EventUtils.synthesizeDrop(dragSrcElement, homeButton, dragData, "copy", window);
 
     let setHomepageDialog = await setHomepageDialogPromise;
     ok(true, "dialog appeared in response to home button drop");
     await BrowserTestUtils.waitForEvent(setHomepageDialog, "load", false);
 
     let setHomepagePromise = new Promise(function(resolve) {
       let observer = {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
         observe(subject, topic, data) {
           is(topic, "nsPref:changed", "observed correct topic");
           is(data, HOMEPAGE_PREF, "observed correct data");
           let modified = Services.prefs.getStringPref(HOMEPAGE_PREF);
           is(modified, homepage, "homepage is set correctly");
           Services.prefs.removeObserver(HOMEPAGE_PREF, observer);
 
           Services.prefs.setStringPref(HOMEPAGE_PREF, "about:mozilla;");
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -542,17 +542,17 @@ function promiseOnBookmarkItemAdded(aExp
         }
       },
       onBeginUpdateBatch() {},
       onEndUpdateBatch() {},
       onItemRemoved() {},
       onItemChanged() {},
       onItemVisited() {},
       onItemMoved() {},
-      QueryInterface: XPCOMUtils.generateQI([
+      QueryInterface: ChromeUtils.generateQI([
         Ci.nsINavBookmarkObserver,
       ])
     };
     info("Waiting for a bookmark to be added");
     PlacesUtils.bookmarks.addObserver(bookmarksObserver);
   });
 }
 
--- a/browser/base/content/test/performance/browser_appmenu.js
+++ b/browser/base/content/test/performance/browser_appmenu.js
@@ -11,46 +11,36 @@ let gCUITestUtils = new CustomizableUITe
  * reflows to the whitelist, you should be modifying your code to avoid the reflow.
  *
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
 const EXPECTED_APPMENU_OPEN_REFLOWS = [
   {
     stack: [
-      "openPopup@chrome://global/content/bindings/popup.xml",
       "openPopup/this._openPopupPromise<@resource:///modules/PanelMultiView.jsm",
     ],
   },
 
   {
     stack: [
-      "get_alignmentPosition@chrome://global/content/bindings/popup.xml",
       "adjustArrowPosition@chrome://global/content/bindings/popup.xml",
       "onxblpopuppositioned@chrome://global/content/bindings/popup.xml",
     ],
 
     maxCount: 3, // This number should only ever go down - never up.
   },
 
   {
     stack: [
-      "get_alignmentPosition@chrome://global/content/bindings/popup.xml",
-      "_calculateMaxHeight@resource:///modules/PanelMultiView.jsm",
-      "handleEvent@resource:///modules/PanelMultiView.jsm",
-    ],
-  },
-
-  {
-    stack: [
       "_calculateMaxHeight@resource:///modules/PanelMultiView.jsm",
       "handleEvent@resource:///modules/PanelMultiView.jsm",
     ],
 
-    maxCount: 6, // This number should only ever go down - never up.
+    maxCount: 7, // This number should only ever go down - never up.
   },
 ];
 
 add_task(async function() {
   await ensureNoPreloadedBrowser();
 
   let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
     "anonid", "textbox-input-box").getBoundingClientRect();
--- a/browser/base/content/test/performance/browser_startup.js
+++ b/browser/base/content/test/performance/browser_startup.js
@@ -69,19 +69,16 @@ const startupPhases = {
       "resource:///modules/BrowserUsageTelemetry.jsm",
       "resource:///modules/ContentCrashHandlers.jsm",
       "resource:///modules/ShellService.jsm",
       "resource://gre/modules/NewTabUtils.jsm",
       "resource://gre/modules/PageThumbs.jsm",
       "resource://gre/modules/PlacesUtils.jsm",
       "resource://gre/modules/Promise.jsm", // imported by devtools during _delayedStartup
       "resource://gre/modules/Preferences.jsm",
-      // Bug 1448944 - This should be in a stricter bucket, but we
-      // load it to check content prefs on the initial about:blank
-      "resource://gre/modules/Sqlite.jsm",
     ]),
     services: new Set([
       "@mozilla.org/browser/search-service;1",
     ])
   }},
 
   // We are at this phase once we are ready to handle user events.
   // Anything loaded at this phase or before gets in the way of the user
@@ -98,16 +95,17 @@ const startupPhases = {
       "resource://gre/modules/BookmarkHTMLUtils.jsm",
       "resource://gre/modules/Bookmarks.jsm",
       "resource://gre/modules/ContextualIdentityService.jsm",
       "resource://gre/modules/CrashSubmit.jsm",
       "resource://gre/modules/FxAccounts.jsm",
       "resource://gre/modules/FxAccountsStorage.jsm",
       "resource://gre/modules/PlacesBackups.jsm",
       "resource://gre/modules/PlacesSyncUtils.jsm",
+      "resource://gre/modules/Sqlite.jsm",
     ]),
     services: new Set([
       "@mozilla.org/browser/annotation-service;1",
       "@mozilla.org/browser/nav-bookmarks-service;1",
     ])
   }},
 
   // Things that are expected to be completely out of the startup path
--- a/browser/base/content/test/performance/browser_urlbar_keyed_search.js
+++ b/browser/base/content/test/performance/browser_urlbar_keyed_search.js
@@ -18,17 +18,16 @@ requestLongerTimeout(5);
 const EXPECTED_REFLOWS_FIRST_OPEN = [
   {
     stack: [
       "_rebuild@chrome://browser/content/search/search.xml",
       "set_popup@chrome://browser/content/search/search.xml",
       "enableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
       "_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
       "urlbar_XBL_Constructor/<@chrome://browser/content/urlbarBindings.xml",
-      "openPopup@chrome://global/content/bindings/popup.xml",
       "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openPopup@chrome://global/content/bindings/autocomplete.xml",
       "set_popupOpen@chrome://global/content/bindings/autocomplete.xml"
     ],
   },
 
   {
@@ -69,17 +68,16 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
       "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
     ],
     maxCount: 6, // This number should only ever go down - never up.
   },
 
   // Bug 1359989
   {
     stack: [
-      "openPopup@chrome://global/content/bindings/popup.xml",
       "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openPopup@chrome://global/content/bindings/autocomplete.xml",
       "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
     ],
   },
 ];
 
--- a/browser/base/content/test/performance/browser_urlbar_search.js
+++ b/browser/base/content/test/performance/browser_urlbar_search.js
@@ -18,17 +18,16 @@ requestLongerTimeout(5);
 const EXPECTED_REFLOWS_FIRST_OPEN = [
   {
     stack: [
       "_rebuild@chrome://browser/content/search/search.xml",
       "set_popup@chrome://browser/content/search/search.xml",
       "enableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
       "_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
       "urlbar_XBL_Constructor/<@chrome://browser/content/urlbarBindings.xml",
-      "openPopup@chrome://global/content/bindings/popup.xml",
       "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openPopup@chrome://global/content/bindings/autocomplete.xml",
       "set_popupOpen@chrome://global/content/bindings/autocomplete.xml"
     ],
   },
 
   {
@@ -69,17 +68,16 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
       "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
     ],
     maxCount: 6, // This number should only ever go down - never up.
   },
 
   // Bug 1359989
   {
     stack: [
-      "openPopup@chrome://global/content/bindings/popup.xml",
       "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openPopup@chrome://global/content/bindings/autocomplete.xml",
       "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
     ],
   },
 ];
 
@@ -111,17 +109,16 @@ const EXPECTED_REFLOWS_SECOND_OPEN = [
       "invalidate@chrome://global/content/bindings/autocomplete.xml"
     ],
     maxCount: 24, // This number should only ever go down - never up.
   },
 
   // Bug 1359989
   {
     stack: [
-      "openPopup@chrome://global/content/bindings/popup.xml",
       "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openPopup@chrome://global/content/bindings/autocomplete.xml",
       "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
     ],
   },
 ];
 
--- a/browser/base/content/test/performance/browser_window_resize.js
+++ b/browser/base/content/test/performance/browser_window_resize.js
@@ -8,19 +8,37 @@
  * is a whitelist that should slowly go away as we improve the performance of
  * the front-end. Instead of adding more reflows to the whitelist, you should
  * be modifying your code to avoid the reflow.
  *
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
 const EXPECTED_REFLOWS = [
-   /**
-   * Nothing here! Please don't add anything new!
-   */
+  {
+    stack: [
+      "onOverflow@resource:///modules/CustomizableUI.jsm",
+    ],
+    maxCount: 48,
+  },
+
+  {
+    stack: [
+      "_moveItemsBackToTheirOrigin@resource:///modules/CustomizableUI.jsm",
+      "_onLazyResize@resource:///modules/CustomizableUI.jsm",
+    ],
+    maxCount: 5,
+  },
+
+  {
+    stack: [
+      "_onLazyResize@resource:///modules/CustomizableUI.jsm",
+    ],
+    maxCount: 4,
+  },
 ];
 
 const gToolbar = document.getElementById("PersonalToolbar");
 
 /**
  * Sets the visibility state on the Bookmarks Toolbar, and
  * waits for it to transition to fully visible.
  *
--- a/browser/base/content/test/performance/head.js
+++ b/browser/base/content/test/performance/head.js
@@ -49,18 +49,18 @@ async function recordReflows(testPromise
       dirtyFrame(win);
     },
 
     reflowInterruptible(start, end) {
       // Interruptible reflows are the reflows caused by the refresh
       // driver ticking. These are fine.
     },
 
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
-                                           Ci.nsISupportsWeakReference])
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIReflowObserver,
+                                            Ci.nsISupportsWeakReference])
   };
 
   let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIWebNavigation)
                     .QueryInterface(Ci.nsIDocShell);
   docShell.addWeakReflowObserver(observer);
 
   let dirtyFrameFn = event => {
--- a/browser/base/content/test/plugins/blocklist_proxy.js
+++ b/browser/base/content/test/plugins/blocklist_proxy.js
@@ -10,19 +10,19 @@ ChromeUtils.import("resource://gre/modul
 SimpleTest.requestFlakyTimeout("Need to simulate blocklist calls actually taking non-0 time to return");
 
 /*
  * A lightweight blocklist proxy for the testing purposes.
  */
 var BlocklistProxy = {
   _uuid: null,
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsIBlocklistService,
-                                         Ci.nsITimerCallback]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsIBlocklistService,
+                                          Ci.nsITimerCallback]),
 
   init() {
     if (!this._uuid) {
       this._uuid =
         Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
                                            .generateUUID();
       Cm.nsIComponentRegistrar.registerFactory(this._uuid, "",
                                                "@mozilla.org/extensions/blocklist;1",
@@ -52,21 +52,18 @@ var BlocklistProxy = {
     return 0; // STATE_NOT_BLOCKED
   },
 
   async getPluginBlocklistState(aPluginTag, aAppVersion, aToolkitVersion) {
     await new Promise(r => setTimeout(r, 150));
     return 0; // STATE_NOT_BLOCKED
   },
 
-  getPluginBlocklistURL(aPluginTag) {
-    return "";
-  },
-
-  getPluginInfoURL(aPluginTag) {
+  async getPluginBlockURL(aPluginTag) {
+    await new Promise(r => setTimeout(r, 150));
     return "";
   },
 };
 
 BlocklistProxy.init();
 addEventListener("unload", () => {
   BlocklistProxy.uninit();
 });
--- a/browser/base/content/test/referrer/browser_referrer_open_link_in_container_tab.js
+++ b/browser/base/content/test/referrer/browser_referrer_open_link_in_container_tab.js
@@ -35,17 +35,17 @@ function startNewTabTestCase(aTestNumber
 
       aContextMenu.addEventListener("popuphidden", function() {
         firstContext.doCommand();
       }, {once: true});
 
       aContextMenu.hidePopup();
     }, {once: true});
 
-    menupopup.showPopup();
+    menupopup.openPopup();
   });
 }
 
 function test() {
   waitForExplicitFinish();
 
   SpecialPowers.pushPrefEnv(
     {set: [["privacy.userContext.enabled", true]]},
--- a/browser/base/content/test/referrer/browser_referrer_open_link_in_container_tab3.js
+++ b/browser/base/content/test/referrer/browser_referrer_open_link_in_container_tab3.js
@@ -31,17 +31,17 @@ function startNewTabTestCase(aTestNumber
 
       aContextMenu.addEventListener("popuphidden", function() {
         firstContext.doCommand();
       }, {once: true});
 
       aContextMenu.hidePopup();
     }, {once: true});
 
-    menupopup.showPopup();
+    menupopup.openPopup();
   });
 }
 
 function test() {
   waitForExplicitFinish();
 
   SpecialPowers.pushPrefEnv(
     {set: [["privacy.userContext.enabled", true]]},
--- a/browser/base/content/test/sync/browser_contextmenu_sendpage.js
+++ b/browser/base/content/test/sync/browser_contextmenu_sendpage.js
@@ -232,17 +232,17 @@ async function openContentContextMenu(se
       centered: true
     },
     gBrowser.selectedBrowser);
   await awaitPopupShown;
 
   if (openSubmenuId) {
     const menuPopup = document.getElementById(openSubmenuId).menupopup;
     const menuPopupPromise = BrowserTestUtils.waitForEvent(menuPopup, "popupshown");
-    menuPopup.showPopup();
+    menuPopup.openPopup();
     await menuPopupPromise;
   }
 }
 
 async function hideContentContextMenu() {
   const contextMenu = document.getElementById("contentAreaContextMenu");
   const awaitPopupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
   contextMenu.hidePopup();
--- a/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar.js
+++ b/browser/base/content/test/urlbar/browser_tabMatchesInAwesomebar.js
@@ -199,17 +199,17 @@ function checkAutocompleteResults(aExpec
         ok(false, "'" + entry + "' should be found in autocomplete");
       }
 
       executeSoon(aCallback);
     },
     setSelectedIndex() {},
     get searchCount() { return this.searches.length; },
     getSearchAt(aIndex) { return this.searches[aIndex]; },
-    QueryInterface: XPCOMUtils.generateQI([
+    QueryInterface: ChromeUtils.generateQI([
       Ci.nsIAutoCompleteInput,
       Ci.nsIAutoCompletePopup,
     ])
   };
 
   info("Searching open pages.");
   gController.startSearch(RESTRICT_TOKEN_OPENPAGE);
 }
--- a/browser/base/content/test/urlbar/browser_urlbar_search_no_speculative_connect_with_client_cert.js
+++ b/browser/base/content/test/urlbar/browser_urlbar_search_no_speculative_connect_with_client_cert.js
@@ -27,17 +27,17 @@ const clientAuthDialogs = {
     ok(expectingChooseCertificate,
        `${expectingChooseCertificate ? "" : "not "}expecting chooseCertificate to be called`);
     is(certList.length, 1, "should have only one client certificate available");
     selectedIndex.value = 0;
     chooseCertificateCalled = true;
     return true;
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIClientAuthDialogs]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIClientAuthDialogs]),
 };
 
 function startServer(cert) {
   let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"]
                     .createInstance(Ci.nsITLSServerSocket);
   tlsServer.init(-1, true, -1);
   tlsServer.serverCert = cert;
 
--- a/browser/base/content/test/urlbar/head.js
+++ b/browser/base/content/test/urlbar/head.js
@@ -57,17 +57,17 @@ function waitForDocLoadAndStopIt(aExpect
           wp.removeProgressListener(progressListener);
 
           let chan = req.QueryInterface(Ci.nsIChannel);
           dump(`waitForDocLoadAndStopIt: Document start: ${chan.URI.spec}\n`);
 
           stopContent(contentStopFromProgressListener, chan.originalURI.spec);
         }
       },
-      QueryInterface: XPCOMUtils.generateQI(["nsISupportsWeakReference"])
+      QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"])
     };
     wp.addProgressListener(progressListener, wp.NOTIFY_STATE_WINDOW);
 
     /**
      * As |this| is undefined and we can't extend |docShell|, adding an unload
      * event handler is the easiest way to ensure the weakly referenced
      * progress listener is kept alive as long as necessary.
      */
--- a/browser/base/content/web-panels.js
+++ b/browser/base/content/web-panels.js
@@ -42,23 +42,17 @@ var panelProgressListener = {
     },
 
     onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
     },
 
     onSecurityChange(aWebProgress, aRequest, aState) {
     },
 
-    QueryInterface(aIID) {
-        if (aIID.equals(Ci.nsIWebProgressListener) ||
-            aIID.equals(Ci.nsISupportsWeakReference) ||
-            aIID.equals(Ci.nsISupports))
-            return this;
-        throw Cr.NS_NOINTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener", "nsISupportsWeakReference"]),
 };
 
 var gLoadFired = false;
 function loadWebPanel(aURI) {
     var panelBrowser = getPanelBrowser();
     if (gLoadFired) {
         panelBrowser.webNavigation
                     .loadURI(aURI, Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
--- a/browser/components/about/nsAboutCapabilities.js
+++ b/browser/components/about/nsAboutCapabilities.js
@@ -62,13 +62,12 @@ nsAboutCapabilities.prototype = {
   },
 
   isWindowPrivate() {
     return PrivateBrowsingUtils.isContentWindowPrivate(this.window);
   },
 
   contractID: "@mozilla.org/aboutcapabilities;1",
   classID: Components.ID("{4c2b1f46-e637-4a91-8108-8a9fb7aab91d}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsIDOMGlobalPropertyInitializer])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer])
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsAboutCapabilities]);
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -4403,46 +4403,28 @@ OverflowableToolbar.prototype = {
     doc.defaultView.updateEditUIVisibility();
     let contextMenuId = this._panel.getAttribute("context");
     if (contextMenuId) {
       let contextMenu = doc.getElementById(contextMenuId);
       gELS.removeSystemEventListener(contextMenu, "command", this, true);
     }
   },
 
-  /**
-   * Avoid re-entrancy in the overflow handling by keeping track of invocations:
-   */
-  _lastOverflowCounter: 0,
-
-  /**
-   * Handle overflow in the toolbar by moving items to the overflow menu.
-   * @param {Event} aEvent
-   *        The overflow event that triggered handling overflow. May be omitted
-   *        in some cases (e.g. when we run this method after overflow handling
-   *        is re-enabled from customize mode, to ensure correct handling of
-   *        initial overflow).
-   */
-  async onOverflow(aEvent) {
-    if (!this._enabled)
+  onOverflow(aEvent) {
+    // The rangeParent check is here because of bug 1111986 and ensuring that
+    // overflow events from the bookmarks toolbar items or similar things that
+    // manage their own overflow don't trigger an overflow on the entire toolbar
+    if (!this._enabled ||
+        (aEvent && aEvent.target != this._toolbar.customizationTarget) ||
+        (aEvent && aEvent.rangeParent))
       return;
 
     let child = this._target.lastChild;
 
-    let thisOverflowResponse = ++this._lastOverflowCounter;
-
-    let win = this._target.ownerGlobal;
-    let [scrollLeftMin, scrollLeftMax] = await win.promiseDocumentFlushed(() => {
-      return [this._target.scrollLeftMin, this._target.scrollLeftMax];
-    });
-    if (win.closed || this._lastOverflowCounter != thisOverflowResponse) {
-      return;
-    }
-
-    while (child && scrollLeftMin != scrollLeftMax) {
+    while (child && this._target.scrollLeftMin != this._target.scrollLeftMax) {
       let prevChild = child.previousSibling;
 
       if (child.getAttribute("overflows") != "false") {
         this._collapsed.set(child.id, this._target.clientWidth);
         child.setAttribute("overflowedItem", true);
         child.setAttribute("cui-anchorid", this._chevron.id);
         CustomizableUIInternal.ensureButtonContextMenu(child, this._toolbar, true);
         CustomizableUIInternal.notifyListeners("onWidgetOverflow", child, this._target);
@@ -4451,70 +4433,40 @@ OverflowableToolbar.prototype = {
         if (!this._addedListener) {
           CustomizableUI.addListener(this);
         }
         if (!CustomizableUI.isSpecialWidget(child.id)) {
           this._toolbar.setAttribute("overflowing", "true");
         }
       }
       child = prevChild;
-      [scrollLeftMin, scrollLeftMax] = await win.promiseDocumentFlushed(() => {
-        return [this._target.scrollLeftMin, this._target.scrollLeftMax];
-      });
-      // If the window has closed or if we re-enter because we were waiting
-      // for layout, stop.
-      if (win.closed || this._lastOverflowCounter != thisOverflowResponse) {
-        return;
-      }
-    }
-
+    }
+
+    let win = this._target.ownerGlobal;
     win.UpdateUrlbarSearchSplitterState();
-    // Reset the counter because we finished handling overflow.
-    this._lastOverflowCounter = 0;
   },
 
   _onResize(aEvent) {
-    // Ignore bubbled-up resize events.
-    if (aEvent.target != aEvent.target.ownerGlobal.top) {
-      return;
-    }
     if (!this._lazyResizeHandler) {
       this._lazyResizeHandler = new DeferredTask(this._onLazyResize.bind(this),
                                                  LAZY_RESIZE_INTERVAL_MS, 0);
     }
     this._lazyResizeHandler.arm();
   },
 
-  /**
-   * Try to move toolbar items back to the toolbar from the overflow menu.
-   * @param {boolean} shouldMoveAllItems
-   *        Whether we should move everything (e.g. because we're being disabled)
-   * @param {number} targetWidth
-   *        Optional; the width of the toolbar in which we can put things.
-   *        Some consumers pass this to avoid reflows.
-   *        While there are items in the list, this width won't change, and so
-   *        we can avoid flushing layout by providing it and/or caching it.
-   *        Note that if `shouldMoveAllItems` is true, we never need the width
-   *        anyway.
-   */
-  _moveItemsBackToTheirOrigin(shouldMoveAllItems, targetWidth) {
+  _moveItemsBackToTheirOrigin(shouldMoveAllItems) {
     let placements = gPlacements.get(this._toolbar.id);
-    let win = this._target.ownerGlobal;
     while (this._list.firstChild) {
       let child = this._list.firstChild;
       let minSize = this._collapsed.get(child.id);
 
-      if (!shouldMoveAllItems && minSize) {
-        if (!targetWidth) {
-          let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-          targetWidth = Math.floor(dwu.getBoundsWithoutFlushing(this._target).width);
-        }
-        if (targetWidth <= minSize) {
-          break;
-        }
+      if (!shouldMoveAllItems &&
+          minSize &&
+          this._target.clientWidth <= minSize) {
+        break;
       }
 
       this._collapsed.delete(child.id);
       let beforeNodeIndex = placements.indexOf(child.id) + 1;
       // If this is a skipintoolbarset item, meaning it doesn't occur in the placements list,
       // we're inserting it at the end. This will mean first-in, first-out (more or less)
       // leading to as little change in order as possible.
       if (beforeNodeIndex == 0) {
@@ -4536,43 +4488,37 @@ OverflowableToolbar.prototype = {
         this._target.appendChild(child);
       }
       child.removeAttribute("cui-anchorid");
       child.removeAttribute("overflowedItem");
       CustomizableUIInternal.ensureButtonContextMenu(child, this._target);
       CustomizableUIInternal.notifyListeners("onWidgetUnderflow", child, this._target);
     }
 
+    let win = this._target.ownerGlobal;
     win.UpdateUrlbarSearchSplitterState();
 
     let collapsedWidgetIds = Array.from(this._collapsed.keys());
     if (collapsedWidgetIds.every(w => CustomizableUI.isSpecialWidget(w))) {
       this._toolbar.removeAttribute("overflowing");
     }
     if (this._addedListener && !this._collapsed.size) {
       CustomizableUI.removeListener(this);
       this._addedListener = false;
     }
   },
 
-  async _onLazyResize() {
+  _onLazyResize() {
     if (!this._enabled)
       return;
 
-    let win = this._target.ownerGlobal;
-    let [min, max, targetWidth] = await win.promiseDocumentFlushed(() => {
-      return [this._target.scrollLeftMin, this._target.scrollLeftMax, this._target.clientWidth];
-    });
-    if (win.closed) {
-      return;
-    }
-    if (min != max) {
+    if (this._target.scrollLeftMin != this._target.scrollLeftMax) {
       this.onOverflow();
     } else {
-      this._moveItemsBackToTheirOrigin(false, targetWidth);
+      this._moveItemsBackToTheirOrigin();
     }
   },
 
   _disable() {
     this._enabled = false;
     this._moveItemsBackToTheirOrigin(true);
     if (this._lazyResizeHandler) {
       this._lazyResizeHandler.disarm();
@@ -4657,17 +4603,17 @@ OverflowableToolbar.prototype = {
     } else if (aNode.previousSibling) {
       // but if it still is, it must have changed places. Bookkeep:
       let prevId = aNode.previousSibling.id;
       let minSize = this._collapsed.get(prevId);
       this._collapsed.set(aNode.id, minSize);
     } else {
       // If it's now the first item in the overflow list,
       // maybe we can return it:
-      this._moveItemsBackToTheirOrigin(false);
+      this._moveItemsBackToTheirOrigin();
     }
   },
 
   findOverflowedInsertionPoints(aNode) {
     let newNodeCanOverflow = aNode.getAttribute("overflows") != "false";
     let areaId = this._toolbar.id;
     let placements = gPlacements.get(areaId);
     let nodeIndex = placements.indexOf(aNode.id);
--- a/browser/components/customizableui/PanelMultiView.jsm
+++ b/browser/components/customizableui/PanelMultiView.jsm
@@ -849,17 +849,17 @@ var PanelMultiView = class extends Assoc
 
     // Set the viewContainer dimensions to make sure only the current view is
     // visible.
     let olderView = reverse ? nextPanelView : prevPanelView;
     this._viewContainer.style.minHeight = olderView.knownHeight + "px";
     this._viewContainer.style.height = prevPanelView.knownHeight + "px";
     this._viewContainer.style.width = prevPanelView.knownWidth + "px";
     // Lock the dimensions of the window that hosts the popup panel.
-    let rect = this._panel.popupBoxObject.getOuterScreenRect();
+    let rect = this._panel.getOuterScreenRect();
     this._panel.setAttribute("width", rect.width);
     this._panel.setAttribute("height", rect.height);
 
     let viewRect;
     if (reverse) {
       // Use the cached size when going back to a previous view, but not when
       // reopening a subview, because its contents may have changed.
       viewRect = { width: nextPanelView.knownWidth,
--- a/browser/components/customizableui/test/browser_976792_insertNodeInWindow.js
+++ b/browser/components/customizableui/test/browser_976792_insertNodeInWindow.js
@@ -221,24 +221,17 @@ add_task(async function() {
   }
 
   for (let id of widgetIds) {
     document.getElementById(id).style.minWidth = "200px";
   }
 
   let originalWindowWidth = window.outerWidth;
   window.resizeTo(kForceOverflowWidthPx, window.outerHeight);
-  // Wait for all the widgets to overflow. We can't just wait for the
-  // `overflowing` attribute because we leave time for layout flushes
-  // inbetween, so it's possible for the timeout to run before the
-  // navbar has "settled"
-  await waitForCondition(() => {
-    return navbar.hasAttribute("overflowing") &&
-      navbar.customizationTarget.lastChild.getAttribute("overflows") == "false";
-  });
+  await waitForCondition(() => navbar.hasAttribute("overflowing"));
 
   // Find last widget that doesn't allow overflowing
   let nonOverflowing = navbar.customizationTarget.lastChild;
   is(nonOverflowing.getAttribute("overflows"), "false", "Last child is expected to not allow overflowing");
   isnot(nonOverflowing.getAttribute("skipintoolbarset"), "true", "Last child is expected to not be skipintoolbarset");
 
   let testWidgetId = kTestWidgetPrefix + 10;
   CustomizableUI.destroyWidget(testWidgetId);
--- a/browser/components/downloads/DownloadsCommon.jsm
+++ b/browser/components/downloads/DownloadsCommon.jsm
@@ -70,18 +70,18 @@ const kDownloadsStringsRequiringPluralFo
   otherDownloads3: true
 };
 
 const kMaxHistoryResultsForLimitedView = 42;
 
 const kPrefBranch = Services.prefs.getBranch("browser.download.");
 
 var PrefObserver = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
   getPref(name) {
     try {
       switch (typeof this.prefs[name]) {
         case "boolean":
           return kPrefBranch.getBoolPref(name);
       }
     } catch (ex) { }
     return this.prefs[name];
--- a/browser/components/enterprisepolicies/EnterprisePolicies.js
+++ b/browser/components/enterprisepolicies/EnterprisePolicies.js
@@ -64,19 +64,19 @@ function EnterprisePoliciesManager() {
   Services.obs.addObserver(this, "final-ui-startup", true);
   Services.obs.addObserver(this, "sessionstore-windows-restored", true);
   Services.obs.addObserver(this, "EnterprisePolicies:Restart", true);
 }
 
 EnterprisePoliciesManager.prototype = {
   // for XPCOM
   classID:          Components.ID("{ea4e1414-779b-458b-9d1f-d18e8efbc145}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsIEnterprisePolicies]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference,
+                                          Ci.nsIEnterprisePolicies]),
 
   // redefine the default factory for XPCOMUtils
   _xpcom_factory: EnterprisePoliciesFactory,
 
   _initialize() {
     let provider = this._chooseProvider();
 
     if (!provider) {
--- a/browser/components/enterprisepolicies/EnterprisePoliciesContent.js
+++ b/browser/components/enterprisepolicies/EnterprisePoliciesContent.js
@@ -46,17 +46,17 @@ function EnterprisePoliciesManagerConten
 
   Services.cpmm.addMessageListener("EnterprisePolicies:DisallowFeature", this);
   Services.cpmm.addMessageListener("EnterprisePolicies:Restart", this);
 }
 
 EnterprisePoliciesManagerContent.prototype = {
   // for XPCOM
   classID:          Components.ID("{dc6358f8-d167-4566-bf5b-4350b5e6a7a2}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIEnterprisePolicies]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIEnterprisePolicies]),
 
   // redefine the default factory for XPCOMUtils
   _xpcom_factory: EnterprisePoliciesFactory,
 
   _status: Ci.nsIEnterprisePolicies.INACTIVE,
 
   _disallowedFeatures: [],
 
--- a/browser/components/enterprisepolicies/helpers/WebsiteFilter.jsm
+++ b/browser/components/enterprisepolicies/helpers/WebsiteFilter.jsm
@@ -74,18 +74,18 @@ function WebsiteFilter(blocklist, except
   if (exceptionArray.length) {
     this._exceptionsPatterns = new MatchPatternSet(exceptionArray);
   }
 
   Services.obs.addObserver(this, "http-on-modify-request", true);
 }
 
 WebsiteFilter.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 
   observe(subject, topic, data) {
     let channel, isDocument = false;
     try {
       channel = subject.QueryInterface(Ci.nsIHttpChannel);
       isDocument = channel.isDocument;
     } catch (e) {
       return;
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_search_engine.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_search_engine.js
@@ -155,21 +155,21 @@ add_task(async function test_opensearch_
 
 add_task(async function test_AddSearchProvider() {
   // Mock the modal error dialog
   let mockPrompter = {
     promptCount: 0,
     alert() {
       this.promptCount++;
     },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPrompt]),
   };
   let windowWatcher = {
     getNewPrompter: () => mockPrompter,
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIWindowWatcher]),
   };
   let origWindowWatcher = Services.ww;
   Services.ww = windowWatcher;
   registerCleanupFunction(() => {
     Services.ww = origWindowWatcher;
   });
 
   let engineURL = getRootDirectory(gTestPath) + "opensearchEngine.xml";
--- a/browser/components/extensions/parent/ext-tabs.js
+++ b/browser/components/extensions/parent/ext-tabs.js
@@ -1164,17 +1164,17 @@ this.tabs = class extends ExtensionAPI {
                       resolve(retval == 0 ? "saved" : "replaced");
                     }
                   },
                   onStatusChange: function(webProgress, request, status, message) {
                     if (status != 0) {
                       resolve(retval == 0 ? "not_saved" : "not_replaced");
                     }
                   },
-                  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener]),
+                  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener]),
                 };
 
                 activeTab.linkedBrowser.print(activeTab.linkedBrowser.outerWindowID, printSettings, printProgressListener);
               } else {
                 // Cancel clicked (retval == 1)
                 resolve("canceled");
               }
             });
--- a/browser/components/feeds/FeedConverter.js
+++ b/browser/components/feeds/FeedConverter.js
@@ -321,25 +321,20 @@ FeedConverter.prototype = {
   onStopRequest(request, context, status) {
     if (this._processor)
       this._processor.onStopRequest(request, context, status);
   },
 
   /**
    * See nsISupports.idl
    */
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIFeedResultListener) ||
-        iid.equals(Ci.nsIStreamConverter) ||
-        iid.equals(Ci.nsIStreamListener) ||
-        iid.equals(Ci.nsIRequestObserver) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFeedResultListener",
+                                          "nsIStreamConverter",
+                                          "nsIStreamListener",
+                                          "nsIRequestObserver"]),
 };
 
 /**
  * Keeps parsed FeedResults around for use elsewhere in the UI after the stream
  * converter completes.
  */
 function FeedResultService() {
 }
@@ -451,23 +446,18 @@ FeedResultService.prototype = {
   },
 
   createInstance(outer, iid) {
     if (outer != null)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return this.QueryInterface(iid);
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIFeedResultService) ||
-        iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFeedResultService",
+                                          "nsIFactory"]),
 };
 
 
 var components = [FeedConverter,
                   FeedResultService];
 
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/browser/components/feeds/FeedWriter.js
+++ b/browser/components/feeds/FeedWriter.js
@@ -976,13 +976,13 @@ FeedWriter.prototype = {
         }
       });
     } else {
       subscribeCallback();
     }
   },
 
   classID: FEEDWRITER_CID,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsIDOMGlobalPropertyInitializer])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsIDOMGlobalPropertyInitializer])
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FeedWriter]);
--- a/browser/components/feeds/WebContentConverter.js
+++ b/browser/components/feeds/WebContentConverter.js
@@ -43,38 +43,28 @@ WebContentConverter.prototype = {
 
   onStartRequest(request, context) {
     let wccr =
         Cc[WCCR_CONTRACTID].
         getService(Ci.nsIWebContentConverterService);
     wccr.loadPreferredHandler(request);
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIStreamConverter) ||
-        iid.equals(Ci.nsIStreamListener) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIStreamConverter",
+                                          "nsIStreamListener"]),
 };
 
 let WebContentConverterFactory = {
   createInstance(outer, iid) {
     if (outer != null)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return new WebContentConverter().QueryInterface(iid);
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory"]),
 };
 
 function ServiceInfo(contentType, uri, name) {
   this._contentType = contentType;
   this._uri = uri;
   this._name = name;
 }
 ServiceInfo.prototype = {
@@ -116,22 +106,17 @@ ServiceInfo.prototype = {
 
   /**
    * See nsIWebContentHandlerInfo
    */
   getHandlerURI(uri) {
     return this._uri.replace(/%s/gi, encodeURIComponent(uri));
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIWebContentHandlerInfo) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIWebContentHandlerInfo"]),
 };
 
 const Utils = {
   makeURI(aURL, aOriginCharset, aBaseURI) {
     return Services.io.newURI(aURL, aOriginCharset, aBaseURI);
   },
 
   checkAndGetURI(aURIString, aContentWindow) {
@@ -860,17 +845,17 @@ WebContentConverterRegistrar.prototype =
     return this.QueryInterface(iid);
   },
 
   classID: WCCR_CLASSID,
 
   /**
    * See nsISupports
    */
-  QueryInterface: XPCOMUtils.generateQI(
+  QueryInterface: ChromeUtils.generateQI(
      [Ci.nsIWebContentConverterService,
       Ci.nsIWebContentHandlerRegistrar,
       Ci.nsIObserver,
       Ci.nsIFactory]),
 
   _xpcom_categories: [{
     category: "app-startup",
     service: true
@@ -1039,17 +1024,17 @@ WebContentConverterRegistrarContent.prot
     return this.QueryInterface(iid);
   },
 
   classID: WCCR_CLASSID,
 
   /**
    * See nsISupports
    */
-  QueryInterface: XPCOMUtils.generateQI(
+  QueryInterface: ChromeUtils.generateQI(
                      [Ci.nsIWebContentHandlerRegistrar,
                       Ci.nsIWebContentConverterService,
                       Ci.nsIFactory])
 };
 
 this.NSGetFactory =
   (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) ?
     XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrarContent]) :
--- a/browser/components/migration/AutoMigrate.jsm
+++ b/browser/components/migration/AutoMigrate.jsm
@@ -674,17 +674,17 @@ const AutoMigrate = {
       return;
     }
 
     let url = Services.urlFormatter.formatURL(rawURL);
     url = url.replace("%IMPORTEDBROWSER%", encodeURIComponent(migrationBrowser));
     chromeWindow.openTrustedLinkIn(url, "tab");
   },
 
-  QueryInterface: XPCOMUtils.generateQI(
+  QueryInterface: ChromeUtils.generateQI(
     [Ci.nsIObserver, Ci.nsINavBookmarkObserver, Ci.nsISupportsWeakReference]
   ),
 
   /**
    * Undo action called by the UndoNotification or by the newtab
    * @param chromeWindow A reference to the window in which to open a link.
    */
   undoAutoMigration(chromeWindow) {
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -80,17 +80,17 @@ function getMigrationBundle() {
  * 3. Set classDescription, contractID and classID for your migrator, and set
  *    NSGetFactory appropriately.
  * 4. If the migrator supports multiple profiles, override the sourceProfiles
  *    Here we default for single-profile migrator.
  * 5. Implement getResources(aProfile) (see below).
  * 6. For startup-only migrators, override |startupOnlyMigrator|.
  */
 var MigratorPrototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserProfileMigrator]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIBrowserProfileMigrator]),
 
   /**
    * OVERRIDE IF AND ONLY IF the source supports multiple profiles.
    *
    * Returns array of profile objects from which data may be imported. The object
    * should have the following keys:
    *   id - a unique string identifier for the profile
    *   name - a pretty name to display to the user in the UI
--- a/browser/components/migration/ProfileMigrator.js
+++ b/browser/components/migration/ProfileMigrator.js
@@ -7,15 +7,15 @@
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource:///modules/MigrationUtils.jsm");
 
 function ProfileMigrator() {
 }
 
 ProfileMigrator.prototype = {
   migrate: MigrationUtils.startupMigration.bind(MigrationUtils),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIProfileMigrator]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIProfileMigrator]),
   classDescription: "Profile Migrator",
   contractID: "@mozilla.org/toolkit/profile-migrator;1",
   classID: Components.ID("6F8BB968-C14F-4D6F-9733-6C6737B35DCE"),
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ProfileMigrator]);
--- a/browser/components/newtab/aboutNewTabService.js
+++ b/browser/components/newtab/aboutNewTabService.js
@@ -87,17 +87,17 @@ AboutNewTabService.prototype = {
   _activityStreamEnabled: false,
   _activityStreamPrerender: false,
   _activityStreamPath: "",
   _activityStreamDebug: false,
   _overridden: false,
   willNotifyUser: false,
 
   classID: Components.ID("{dfcd2adc-7867-4d3a-ba70-17501f208142}"),
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIAboutNewTabService,
     Ci.nsIObserver
   ]),
   _xpcom_categories: [{
     service: true
   }],
 
   observe(subject, topic, data) {
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -281,20 +281,20 @@ nsBrowserContentHandler.prototype = {
     createInstance: function bch_factory_ci(outer, iid) {
       if (outer)
         throw Cr.NS_ERROR_NO_AGGREGATION;
       return gBrowserContentHandler.QueryInterface(iid);
     }
   },
 
   /* nsISupports */
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler,
-                                         Ci.nsIBrowserHandler,
-                                         Ci.nsIContentHandler,
-                                         Ci.nsICommandLineValidator]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsICommandLineHandler,
+                                          Ci.nsIBrowserHandler,
+                                          Ci.nsIContentHandler,
+                                          Ci.nsICommandLineValidator]),
 
   /* nsICommandLineHandler */
   handle: function bch_handle(cmdLine) {
     if (cmdLine.handleFlag("browser", false)) {
       openBrowserWindow(cmdLine);
       cmdLine.preventDefault = true;
     }
 
@@ -692,23 +692,17 @@ function handURIToExistingBrowser(uri, l
 
 function nsDefaultCommandLineHandler() {
 }
 
 nsDefaultCommandLineHandler.prototype = {
   classID: Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}"),
 
   /* nsISupports */
-  QueryInterface: function dch_QI(iid) {
-    if (!iid.equals(Ci.nsISupports) &&
-        !iid.equals(Ci.nsICommandLineHandler))
-      throw Cr.NS_ERROR_NO_INTERFACE;
-
-    return this;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsICommandLineHandler"]),
 
   _haveProfile: false,
 
   /* nsICommandLineHandler */
   handle: function dch_handle(cmdLine) {
     var urilist = [];
 
     if (AppConstants.platform == "win") {
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2724,18 +2724,18 @@ BrowserGlue.prototype = {
     } else {
       AppMenuNotifications.removeNotification("fxa-needs-authentication");
     }
   },
 
   // for XPCOM
   classID:          Components.ID("{eab9012e-5f74-4cbc-b2b5-a590235513cc}"),
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 
   _xpcom_factory: XPCOMUtils.generateSingletonFactory(BrowserGlue),
 };
 
 /**
  * ContentPermissionIntegration is responsible for showing the user
  * simple permission prompts when content requests additional
  * capabilities.
@@ -2784,17 +2784,17 @@ const ContentPermissionIntegration = {
   },
 };
 
 function ContentPermissionPrompt() {}
 
 ContentPermissionPrompt.prototype = {
   classID:          Components.ID("{d8903bf6-68d5-4e97-bcd1-e4d3012f721a}"),
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionPrompt]),
 
   /**
    * This implementation of nsIContentPermissionPrompt.prompt ensures
    * that there's only one nsIContentPermissionType in the request,
    * and that it's of type nsIContentPermissionType. Failing to
    * satisfy either of these conditions will result in this method
    * throwing NS_ERRORs. If the combined ContentPermissionIntegration
    * cannot construct a prompt for this particular request, an
@@ -3037,17 +3037,17 @@ var DefaultBrowserCheck = {
  */
 var JawsScreenReaderVersionCheck = {
   _prompted: false,
 
   init() {
     Services.obs.addObserver(this, "a11y-init-or-shutdown", true);
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
 
   observe(subject, topic, data) {
     if (topic == "a11y-init-or-shutdown" && data == "1") {
       Services.tm.dispatchToMainThread(() => this._checkVersionAndPrompt());
     }
   },
 
   onWindowsRestored() {
--- a/browser/components/payments/content/paymentDialogWrapper.js
+++ b/browser/components/payments/content/paymentDialogWrapper.js
@@ -35,17 +35,17 @@ XPCOMUtils.defineLazyGetter(this, "formA
 });
 
 var paymentDialogWrapper = {
   componentsLoaded: new Map(),
   frame: null,
   mm: null,
   request: null,
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference,
   ]),
 
   /**
    * Note: This method is async because formAutofillStorage plans to become async.
    *
    * @param {string} guid
--- a/browser/components/payments/paymentUIService.js
+++ b/browser/components/payments/paymentUIService.js
@@ -32,17 +32,17 @@ function PaymentUIService() {
       prefix: "Payment UI Service",
     });
   });
   this.log.debug("constructor");
 }
 
 PaymentUIService.prototype = {
   classID: Components.ID("{01f8bd55-9017-438b-85ec-7c15d2b35cdc}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
   DIALOG_URL: "chrome://payments/content/paymentDialogWrapper.xhtml",
   REQUEST_ID_PREFIX: "paymentRequest-",
 
   // nsIPaymentUIService implementation:
 
   showPayment(requestId) {
     this.log.debug("showPayment:", requestId);
     let chromeWindow = Services.wm.getMostRecentWindow("navigator:browser");
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -367,22 +367,17 @@ var BookmarkPropertiesPanel = {
           this._height += -oldHeight + newHeight;
           elementsHeight.set(id, newHeight);
         }
         break;
     }
   },
 
   // nsISupports
-  QueryInterface: function BPP_QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_NOINTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI([]),
 
   _element: function BPP__element(aID) {
     return document.getElementById("editBMPanel_" + aID);
   },
 
   onDialogUnload() {
     // gEditItemOverlay does not exist anymore here, so don't rely on it.
     this._mutationObserver.disconnect();
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -14,16 +14,19 @@ function PlacesViewBase(aPlace, aOptions
   if ("viewElt" in aOptions)
     this._viewElt = aOptions.viewElt;
   this.options = aOptions;
   this._controller = new PlacesController(this);
   this.place = aPlace;
   this._viewElt.controllers.appendController(this._controller);
 }
 
+PlacesViewBase.interfaces = [Ci.nsINavHistoryResultObserver,
+                             Ci.nsISupportsWeakReference];
+
 PlacesViewBase.prototype = {
   // The xul element that holds the entire view.
   _viewElt: null,
   get viewElt() {
     return this._viewElt;
   },
 
   get associatedElement() {
@@ -36,19 +39,18 @@ PlacesViewBase.prototype = {
 
   // The xul element that represents the root container.
   _rootElt: null,
 
   // Set to true for views that are represented by native widgets (i.e.
   // the native mac menu).
   _nativeView: false,
 
-  QueryInterface: XPCOMUtils.generateQI(
-    [Ci.nsINavHistoryResultObserver,
-     Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI(
+    PlacesViewBase.interfaces),
 
   _place: "",
   get place() {
     return this._place;
   },
   set place(val) {
     this._place = val;
 
@@ -1003,22 +1005,18 @@ function PlacesToolbar(aPlace) {
 }
 
 PlacesToolbar.prototype = {
   __proto__: PlacesViewBase.prototype,
 
   _cbEvents: ["dragstart", "dragover", "dragexit", "dragend", "drop",
               "mousemove", "mouseover", "mouseout"],
 
-  QueryInterface: function PT_QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsITimerCallback))
-      return this;
-
-    return PlacesViewBase.prototype.QueryInterface.apply(this, arguments);
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsITimerCallback",
+                                          ...PlacesViewBase.interfaces]),
 
   uninit: function PT_uninit() {
     this._removeEventListeners(this._viewElt, this._cbEvents, false);
     this._removeEventListeners(this._rootElt, ["popupshowing", "popuphidden"],
                                true);
     this._removeEventListeners(this._rootElt, ["overflow", "underflow"], true);
     this._removeEventListeners(window, ["resize", "unload"], false);
     this._removeEventListeners(gBrowser.tabContainer, ["TabOpen", "TabClose"], false);
@@ -1167,25 +1165,21 @@ PlacesToolbar.prototype = {
         // the overflow status of the toolbar.
         if (aEvent.target == aEvent.currentTarget) {
           this.updateNodesVisibility();
         }
         break;
       case "overflow":
         if (!this._isOverflowStateEventRelevant(aEvent))
           return;
-        // Avoid triggering overflow in containers if possible
-        aEvent.stopPropagation();
         this._onOverflow();
         break;
       case "underflow":
         if (!this._isOverflowStateEventRelevant(aEvent))
           return;
-        // Avoid triggering underflow in containers if possible
-        aEvent.stopPropagation();
         this._onUnderflow();
         break;
       case "TabOpen":
       case "TabClose":
         this.updateNodesVisibility();
         break;
       case "dragstart":
         this._onDragStart(aEvent);
@@ -1970,20 +1964,16 @@ function PlacesPanelMenuView(aPlace, aVi
   this.options = aOptions;
 
   PlacesViewBase.call(this, aPlace, aOptions);
 }
 
 PlacesPanelMenuView.prototype = {
   __proto__: PlacesViewBase.prototype,
 
-  QueryInterface: function PAMV_QueryInterface(aIID) {
-    return PlacesViewBase.prototype.QueryInterface.apply(this, arguments);
-  },
-
   uninit: function PAMV_uninit() {
     PlacesViewBase.prototype.uninit.apply(this, arguments);
   },
 
   _insertNewItem:
   function PAMV__insertNewItem(aChild, aInsertionNode, aBefore = null) {
     this._domNodes.delete(aChild);
 
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -83,17 +83,17 @@ PlacesController.prototype = {
    */
   _view: null,
 
   // This is used in certain views to disable user actions on the places tree
   // views. This avoids accidental deletion/modification when the user is not
   // actually organising the trees.
   disableUserActions: false,
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIClipboardOwner
   ]),
 
   // nsIClipboardOwner
   LosingOwnership: function PC_LosingOwnership(aXferable) {
     this.cutNodes = [];
   },
 
--- a/browser/components/places/content/editBookmark.js
+++ b/browser/components/places/content/editBookmark.js
@@ -460,17 +460,17 @@ var gEditItemOverlay = {
                                       this._folderMenuList.selectedIndex);
 
     // Hide the folders-separator if no folder is annotated as recently-used
     this._element("foldersSeparator").hidden = (menupopup.childNodes.length <= 6);
     this._folderMenuList.disabled = this.readOnly;
   },
 
   QueryInterface:
-  XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]),
+  ChromeUtils.generateQI([Ci.nsINavBookmarkObserver]),
 
   _element(aID) {
     return document.getElementById("editBMPanel_" + aID);
   },
 
   uninitPanel(aHideCollapsibleElements) {
     if (aHideCollapsibleElements) {
       // Hide the folder tree if it was previously visible.
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -211,17 +211,17 @@
         },
 
         notify: function OF__notify(aTimer) {
           // Function to process all timer notifications.
 
           if (aTimer == this._folder.openTimer) {
             // Timer to open a submenu that's being dragged over.
             this._folder.elt.lastChild.setAttribute("autoopened", "true");
-            this._folder.elt.lastChild.showPopup(this._folder.elt);
+            this._folder.elt.lastChild.openPopup();
             this._folder.openTimer = null;
           } else if (aTimer == this._folder.closeTimer) {
             // Timer to close a submenu that's been dragged off of.
             // Only close the submenu if the mouse isn't being dragged over any
             // of its child menus.
             var draggingOverChild = PlacesControllerDragHelper
                                     .draggingOverChildNode(this._folder.elt);
             if (draggingOverChild)
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -191,22 +191,17 @@ var PlacesOrganizer = {
 
     if (!Services.policies.isAllowed("profileImport")) {
       document.getElementById("OrganizerCommand_browserImport").setAttribute("disabled", true);
     }
 
     ContentArea.focus();
   },
 
-  QueryInterface: function PO_QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_NOINTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI([]),
 
   handleEvent: function PO_handleEvent(aEvent) {
     if (aEvent.type != "AppCommand")
       return;
 
     aEvent.stopPropagation();
     switch (aEvent.command) {
       case "Back":
--- a/browser/components/places/tests/browser/browser_editBookmark_keywords.js
+++ b/browser/components/places/tests/browser/browser_editBookmark_keywords.js
@@ -11,17 +11,17 @@ add_task(async function() {
         onItemAdded() {},
         onItemRemoved() {},
         onItemVisited() {},
         onItemMoved() {},
         onItemChanged(id, property, isAnno, value) {
           PlacesUtils.bookmarks.removeObserver(this);
           resolve({ property, value });
         },
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver])
+        QueryInterface: ChromeUtils.generateQI([Ci.nsINavBookmarkObserver])
       });
     });
   }
 
   let tab = await BrowserTestUtils.openNewForegroundTab({
     gBrowser,
     opening: TEST_URL,
     waitForStateStop: true
--- a/browser/components/places/tests/browser/browser_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_views_liveupdate.js
@@ -122,17 +122,17 @@ add_task(async function test() {
   }
 });
 
 /**
  * The observer is where magic happens, for every change we do it will look for
  * nodes positions in the affected views.
  */
 var bookmarksObserver = {
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsINavBookmarkObserver,
     Ci.nsIAnnotationObserver
   ]),
 
   // nsIAnnotationObserver
   onItemAnnotationSet() {},
   onItemAnnotationRemoved() {},
   onPageAnnotationSet() {},
@@ -270,17 +270,17 @@ function getNodeForToolbarItem(aItemId, 
         let valid = aValidator ? aValidator(child) : true;
         return [child._placesNode, i - staticNodes, valid];
       }
 
       // Don't search in queries, they could contain our item in a
       // different position.  Search only folders
       if (PlacesUtils.nodeIsFolder(child._placesNode)) {
         var popup = child.lastChild;
-        popup.showPopup(popup);
+        popup.openPopup();
         var foundNode = findNode(popup);
         popup.hidePopup();
         if (foundNode[0] != null)
           return foundNode;
       }
     }
     return [null, null];
   }
--- a/browser/components/places/tests/unit/head_bookmarks.js
+++ b/browser/components/places/tests/unit/head_bookmarks.js
@@ -71,17 +71,17 @@ function rebuildSmartBookmarks() {
   let consoleListener = {
     observe(aMsg) {
       if (aMsg.message.startsWith("[JavaScript Warning:")) {
         // TODO (Bug 1300416): Ignore spurious strict warnings.
         return;
       }
       do_throw("Got console message: " + aMsg.message);
     },
-    QueryInterface: XPCOMUtils.generateQI([ Ci.nsIConsoleListener ]),
+    QueryInterface: ChromeUtils.generateQI([ Ci.nsIConsoleListener ]),
   };
   Services.console.reset();
   Services.console.registerListener(consoleListener);
   registerCleanupFunction(() => {
     try {
       Services.console.unregisterListener(consoleListener);
     } catch (ex) { /* will likely fail */ }
   });
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -1314,17 +1314,17 @@ var gMainPane = {
     Services.prefs.removeObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
 
     Services.prefs.removeObserver(PREF_CONTAINERS_EXTENSION, this);
   },
 
 
   // nsISupports
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
   // nsIObserver
 
   async observe(aSubject, aTopic, aData) {
     if (aTopic == "nsPref:changed") {
       if (aData == PREF_CONTAINERS_EXTENSION) {
         this.readBrowserContainersCheckbox();
         return;
@@ -3017,24 +3017,17 @@ FeedHandlerInfo.prototype = {
       return this._possibleApplicationHandlers;
 
     // A minimal implementation of nsIMutableArray.  It only supports the two
     // methods its callers invoke, namely appendElement and nsIArray::enumerate.
     this._possibleApplicationHandlers = {
       _inner: [],
       _removed: [],
 
-      QueryInterface(aIID) {
-        if (aIID.equals(Ci.nsIMutableArray) ||
-          aIID.equals(Ci.nsIArray) ||
-          aIID.equals(Ci.nsISupports))
-          return this;
-
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      },
+      QueryInterface: ChromeUtils.generateQI(["nsIMutableArray", "nsIArray"]),
 
       get length() {
         return this._inner.length;
       },
 
       enumerate() {
         return new ArrayEnumerator(this._inner);
       },
--- a/browser/components/preferences/in-content/tests/browser_advanced_update.js
+++ b/browser/components/preferences/in-content/tests/browser_advanced_update.js
@@ -13,17 +13,17 @@ const mockUpdateManager = {
   contractId: "@mozilla.org/updates/update-manager;1",
 
   _mockClassId: uuidGenerator.generateUUID(),
 
   _originalClassId: "",
 
   _originalFactory: null,
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateManager]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIUpdateManager]),
 
   createInstance(outer, iiD) {
     if (outer) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
     return this.QueryInterface(iiD);
   },
 
--- a/browser/components/preferences/translation.js
+++ b/browser/components/preferences/translation.js
@@ -65,17 +65,17 @@ Tree.prototype = {
     return "";
   },
   getColumnProperties(column) {
     return "";
   },
   getCellProperties(row, column) {
     return "";
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITreeView])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsITreeView])
 };
 
 function Lang(aCode, label) {
   this.langCode = aCode;
   this._label = label;
 }
 
 Lang.prototype = {
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js
@@ -83,17 +83,17 @@ add_task(async function test_toggleTrack
 
   let { win, tab } = await openAboutPrivateBrowsing();
 
   // Set up the observer for the preference change before triggering the action.
   let prefBranch =
       Services.prefs.getBranch("privacy.trackingprotection.pbmode.");
   let waitForPrefChanged = () => new Promise(resolve => {
     let prefObserver = {
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
       observe() {
         prefBranch.removeObserver("enabled", prefObserver);
         resolve();
       },
     };
     prefBranch.addObserver("enabled", prefObserver);
   });
 
--- a/browser/components/search/test/head.js
+++ b/browser/components/search/test/head.js
@@ -88,18 +88,18 @@ let promiseStateChangeFrameScript = "dat
   () => {
     ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
     /* globals docShell, sendAsyncMessage */
 
     const global = this;
     const LISTENER = Symbol("listener");
     let listener = {
-      QueryInterface: XPCOMUtils.generateQI(["nsISupportsWeakReference",
-                                             "nsIWebProgressListener"]),
+      QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference",
+                                              "nsIWebProgressListener"]),
 
       onStateChange: function onStateChange(webProgress, req, flags, status) {
         // Only care about top-level document starts
         if (!webProgress.isTopLevel ||
             !(flags & Ci.nsIWebProgressListener.STATE_START)) {
           return;
         }
 
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -366,17 +366,17 @@ ContentRestoreInternal.prototype = {
 function HistoryListener(docShell, callback) {
   let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
   webNavigation.sessionHistory.legacySHistory.addSHistoryListener(this);
 
   this.webNavigation = webNavigation;
   this.callback = callback;
 }
 HistoryListener.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsISHistoryListener,
     Ci.nsISupportsWeakReference
   ]),
 
   uninstall() {
     let shistory = this.webNavigation.sessionHistory.legacySHistory;
     if (shistory) {
       shistory.removeSHistoryListener(this);
@@ -446,17 +446,17 @@ function ProgressListener(docShell, call
                             .getInterface(Ci.nsIWebProgress);
   webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
 
   this.webProgress = webProgress;
   this.callbacks = callbacks;
 }
 
 ProgressListener.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIWebProgressListener,
     Ci.nsISupportsWeakReference
   ]),
 
   uninstall() {
     this.webProgress.removeProgressListener(this);
   },
 
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -433,17 +433,17 @@ var SessionStore = {
     }
   },
 };
 
 // Freeze the SessionStore object. We don't want anyone to modify it.
 Object.freeze(SessionStore);
 
 var SessionStoreInternal = {
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
   ]),
 
   _globalState: new GlobalState(),
 
   // A counter to be used to generate a unique ID for each closed tab or window.
   _nextClosedId: 0,
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -137,18 +137,18 @@ var StateChangeNotifier = {
 
     if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
       this.notifyObservers("onPageLoadStarted");
     } else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
       this.notifyObservers("onPageLoadCompleted");
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                          Ci.nsISupportsWeakReference])
 };
 
 /**
  * Listens for and handles content events that we need for the
  * session store service to be notified of state changes in content.
  */
 var EventListener = {
 
@@ -442,17 +442,17 @@ var SessionHistoryListener = {
   OnLengthChanged(aCount) {
     // Ignore, the method is implemented so that XPConnect doesn't throw!
   },
 
   OnIndexChanged(aIndex) {
     // Ignore, the method is implemented so that XPConnect doesn't throw!
   },
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsISHistoryListener,
     Ci.nsISupportsWeakReference
   ])
 };
 
 /**
  * Listens for scroll position changes. Whenever the user scrolls the top-most
  * frame we update the scroll position and will restore it when requested.
@@ -694,18 +694,18 @@ var PrivacyListener = {
     }
   },
 
   // Ci.nsIPrivacyTransitionObserver
   privateModeChanged(enabled) {
     MessageQueue.push("isPrivate", () => enabled || null);
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrivacyTransitionObserver,
-                                         Ci.nsISupportsWeakReference])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPrivacyTransitionObserver,
+                                          Ci.nsISupportsWeakReference])
 };
 
 /**
  * A message queue that takes collected data and will take care of sending it
  * to the chrome process. It allows flushing using synchronous messages and
  * takes care of any race conditions that might occur because of that. Changes
  * will be batched if they're pushed in quick succession to avoid a message
  * flood.
--- a/browser/components/sessionstore/nsSessionStartup.js
+++ b/browser/components/sessionstore/nsSessionStartup.js
@@ -351,15 +351,15 @@ SessionStartup.prototype = {
   /**
    * Get whether the previous session crashed.
    */
   get previousSessionCrashed() {
     return this._previousSessionCrashed;
   },
 
   /* ........ QueryInterface .............. */
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsISessionStartup]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference,
+                                          Ci.nsISessionStartup]),
   classID: Components.ID("{ec7a6c20-e081-11da-8ad9-0800200c9a66}")
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SessionStartup]);
--- a/browser/components/sessionstore/test/browser_599909.js
+++ b/browser/components/sessionstore/test/browser_599909.js
@@ -106,17 +106,17 @@ function checkAutocompleteResults(aExpec
 
       executeSoon(aCallback);
     },
     setSelectedIndex() {},
     get searchCount() { return this.searches.length; },
     getSearchAt(aIndex) {
       return this.searches[aIndex];
     },
-    QueryInterface: XPCOMUtils.generateQI([
+    QueryInterface: ChromeUtils.generateQI([
       Ci.nsIAutoCompleteInput,
       Ci.nsIAutoCompletePopup,
     ])
   };
 
   info("Searching open pages.");
   gController.startSearch(RESTRICT_TOKEN_OPENPAGE);
 }
--- a/browser/components/sessionstore/test/browser_async_remove_tab.js
+++ b/browser/components/sessionstore/test/browser_async_remove_tab.js
@@ -43,17 +43,17 @@ function promiseNewLocationAndHistoryEnt
 
     return new Promise(resolve => {
       let listener = {
         OnHistoryReplaceEntry() {
           shistory.removeSHistoryListener(this);
           resolve();
         },
 
-        QueryInterface: XPCOMUtils.generateQI([
+        QueryInterface: ChromeUtils.generateQI([
           Ci.nsISHistoryListener,
           Ci.nsISupportsWeakReference
         ])
       };
 
       shistory.addSHistoryListener(listener);
 
       /* Keep the weak shistory listener alive. */
@@ -73,17 +73,17 @@ function promiseHistoryEntryReplacedNonR
     let shistory = browser.webNavigation.sessionHistory.legacySHistory;
 
     let listener = {
       OnHistoryReplaceEntry() {
         shistory.removeSHistoryListener(this);
         executeSoon(resolve);
       },
 
-      QueryInterface: XPCOMUtils.generateQI([
+      QueryInterface: ChromeUtils.generateQI([
         Ci.nsISHistoryListener,
         Ci.nsISupportsWeakReference
       ])
     };
 
     shistory.addSHistoryListener(listener);
     listeners.set(browser, listener);
   });
--- a/browser/components/sessionstore/test/browser_not_collect_when_idle.js
+++ b/browser/components/sessionstore/test/browser_not_collect_when_idle.js
@@ -20,17 +20,17 @@ var idleService = {
 
   _fireObservers(state) {
     for (let observer of this._observers.values()) {
       observer.observe(observer, state, null);
       this._activity.observerFires.push(state);
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIIdleService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIIdleService]),
   idleTime: 19999,
 
   addIdleObserver(observer, time) {
     this._observers.add(observer);
     this._activity.addCalls.push(time);
   },
 
   removeIdleObserver(observer, time) {
--- a/browser/components/sessionstore/test/browser_parentProcessRestoreHash.js
+++ b/browser/components/sessionstore/test/browser_parentProcessRestoreHash.js
@@ -7,17 +7,17 @@ const SELFCHROMEURL =
 const Cm = Components.manager;
 
 const TESTCLASSID = "78742c04-3630-448c-9be3-6c5070f062de";
 
 const TESTURL = "about:testpageforsessionrestore#foo";
 
 
 let TestAboutPage = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIAboutModule]),
   getURIFlags(aURI) {
     // No CAN_ or MUST_LOAD_IN_CHILD means this loads in the parent:
     return Ci.nsIAboutModule.ALLOW_SCRIPT |
            Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
            Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
   },
 
   newChannel(aURI, aLoadInfo) {
--- a/browser/components/sessionstore/test/content.js
+++ b/browser/components/sessionstore/test/content.js
@@ -41,17 +41,17 @@ var historyListener = {
     sendAsyncMessage("ss-test:OnHistoryReload");
     return true;
   },
 
   OnHistoryReplaceEntry() {
     sendAsyncMessage("ss-test:OnHistoryReplaceEntry");
   },
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsISHistoryListener,
     Ci.nsISupportsWeakReference
   ])
 };
 
 var {sessionHistory} = docShell.QueryInterface(Ci.nsIWebNavigation);
 if (sessionHistory) {
   sessionHistory.legacySHistory.addSHistoryListener(historyListener);
--- a/browser/components/shell/HeadlessShell.jsm
+++ b/browser/components/shell/HeadlessShell.jsm
@@ -34,18 +34,18 @@ function loadContentWindow(webNavigation
         let contentWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                                     .getInterface(Ci.nsIDOMWindow);
         progressListeners.delete(progressListener);
         webProgress.removeProgressListener(progressListener);
         contentWindow.addEventListener("load", (event) => {
           resolve(contentWindow);
         }, { once: true });
       },
-      QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
-                                             "nsISupportsWeakReference"])
+      QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
+                                              "nsISupportsWeakReference"])
     };
     progressListeners.set(progressListener, progressListener);
     webProgress.addProgressListener(progressListener,
                                     Ci.nsIWebProgress.NOTIFY_LOCATION);
   });
 }
 
 async function takeScreenshot(fullWidth, fullHeight, contentWidth, contentHeight, path, url) {
--- a/browser/components/tests/browser/browser_contentpermissionprompt.js
+++ b/browser/components/tests/browser/browser_contentpermissionprompt.js
@@ -21,17 +21,17 @@ XPCOMUtils.defineLazyServiceGetter(this,
  *        Example: "geo", "desktop-notification".
  * @return nsIContentPermissionType implementation.
  */
 function MockContentPermissionType(type) {
   this.type = type;
 }
 
 MockContentPermissionType.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionType]),
   // We expose the wrappedJSObject so that we can be sure
   // in some of our tests that we're passing the right
   // nsIContentPermissionType around.
   wrappedJSObject: this,
 };
 
 /**
  * This is a partial implementation of nsIContentPermissionRequest.
@@ -44,17 +44,17 @@ MockContentPermissionType.prototype = {
 function MockContentPermissionRequest(typesArray) {
   this.types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
   for (let type of typesArray) {
     this.types.appendElement(type);
   }
 }
 
 MockContentPermissionRequest.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionRequest]),
   // We expose the wrappedJSObject so that we can be sure
   // in some of our tests that we're passing the right
   // nsIContentPermissionRequest around.
   wrappedJSObject: this,
   // For some of our tests, we want to make sure that the
   // request is cancelled, so we add some instrumentation here
   // to check that cancel() is called.
   cancel() {
@@ -95,17 +95,17 @@ add_task(async function test_multiple_ty
 
 /**
  * Tests that if the nsIContentPermissionRequest has a type that
  * does not implement nsIContentPermissionType that NS_NOINTERFACE
  * is thrown, and the request is cancelled.
  */
 add_task(async function test_not_permission_type() {
   let mockRequest = new MockContentPermissionRequest([
-    { QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]) },
+    { QueryInterface: ChromeUtils.generateQI([]) },
   ]);
 
   Assert.throws(() => { ContentPermissionPrompt.prompt(mockRequest); },
                 /NS_NOINTERFACE/);
   Assert.ok(mockRequest.cancelled, "Should have cancelled the request.");
 });
 
 /**
--- a/browser/components/tests/startupRecorder.js
+++ b/browser/components/tests/startupRecorder.js
@@ -52,17 +52,17 @@ function startupRecorder() {
     code: {},
     prefStats: {},
   };
   this.done = new Promise(resolve => { this._resolve = resolve; });
 }
 startupRecorder.prototype = {
   classID: Components.ID("{11c095b2-e42e-4bdf-9dd0-aed87595f6a4}"),
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
   record(name) {
     if (!Services.prefs.getBoolPref("browser.startup.record", false))
       return;
 
     this.data.code[name] = {
       components: this.loader.loadedComponents(),
       modules: this.loader.loadedModules(),
--- a/browser/components/translation/TranslationContentHandler.jsm
+++ b/browser/components/translation/TranslationContentHandler.jsm
@@ -100,18 +100,18 @@ TranslationContentHandler.prototype = {
         state: STATE_OFFER,
         originalShown: true,
         detectedLanguage: result.language
       };
       this.global.sendAsyncMessage("Translation:DocumentState", data);
     });
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                          Ci.nsISupportsWeakReference]),
 
   receiveMessage(msg) {
     switch (msg.name) {
       case "Translation:TranslateDocument":
       {
         ChromeUtils.import("resource:///modules/translation/TranslationDocument.jsm");
 
         // If a TranslationDocument already exists for this document, it should
--- a/browser/components/uitour/test/browser_UITour.js
+++ b/browser/components/uitour/test/browser_UITour.js
@@ -238,17 +238,17 @@ var tests = [
   function test_info_1(done) {
     let popup = document.getElementById("UITourTooltip");
     let title = document.getElementById("UITourTooltipTitle");
     let desc = document.getElementById("UITourTooltipDescription");
     let icon = document.getElementById("UITourTooltipIcon");
     let buttons = document.getElementById("UITourTooltipButtons");
 
     popup.addEventListener("popupshown", function() {
-      is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
+      is(popup.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
       is(title.textContent, "test title", "Popup should have correct title");
       is(desc.textContent, "test text", "Popup should have correct description text");
       is(icon.src, "", "Popup should have no icon");
       is(buttons.hasChildNodes(), false, "Popup should have no buttons");
 
       popup.addEventListener("popuphidden", function() {
         popup.addEventListener("popupshown", function() {
           done();
@@ -266,30 +266,30 @@ var tests = [
     let popup = document.getElementById("UITourTooltip");
     let title = document.getElementById("UITourTooltipTitle");
     let desc = document.getElementById("UITourTooltipDescription");
     let icon = document.getElementById("UITourTooltipIcon");
     let buttons = document.getElementById("UITourTooltipButtons");
 
     await showInfoPromise("urlbar", "urlbar title", "urlbar text");
 
-    is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
+    is(popup.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
     is(title.textContent, "urlbar title", "Popup should have correct title");
     is(desc.textContent, "urlbar text", "Popup should have correct description text");
     is(icon.src, "", "Popup should have no icon");
     is(buttons.hasChildNodes(), false, "Popup should have no buttons");
 
     // Place the search bar in the navigation toolbar temporarily.
     await SpecialPowers.pushPrefEnv({ set: [
       ["browser.search.widget.inNavBar", true],
     ]});
 
     await showInfoPromise("search", "search title", "search text");
 
-    is(popup.popupBoxObject.anchorNode, document.getElementById("searchbar"), "Popup should be anchored to the searchbar");
+    is(popup.anchorNode, document.getElementById("searchbar"), "Popup should be anchored to the searchbar");
     is(title.textContent, "search title", "Popup should have correct title");
     is(desc.textContent, "search text", "Popup should have correct description text");
 
     await SpecialPowers.popPrefEnv();
   }),
   function test_getConfigurationVersion(done) {
     function callback(result) {
       ok(typeof result.version !== "undefined", "Check version isn't undefined.");
--- a/browser/components/uitour/test/browser_UITour_defaultBrowser.js
+++ b/browser/components/uitour/test/browser_UITour_defaultBrowser.js
@@ -5,17 +5,17 @@ var gContentAPI;
 var gContentWindow;
 var setDefaultBrowserCalled = false;
 
 Services.scriptloader
   .loadSubScript("chrome://mochikit/content/tests/SimpleTest/MockObjects.js", this);
 
 function MockShellService() {}
 MockShellService.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIShellService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIShellService]),
   isDefaultBrowser(aStartupCheck, aForAllTypes) { return false; },
   setDefaultBrowser(aClaimAllTypes, aForAllUsers) {
     setDefaultBrowserCalled = true;
   },
   shouldCheckDefaultBrowser: false,
   canSetDesktopBackground: false,
   BACKGROUND_TILE: 1,
   BACKGROUND_STRETCH: 2,
--- a/browser/components/uitour/test/browser_fxa.js
+++ b/browser/components/uitour/test/browser_fxa.js
@@ -31,17 +31,17 @@ var tests = [
   }),
 
   taskify(async function test_highlight_accountStatus_loggedIn() {
     gSync.updateAllUI({ status: UIState.STATUS_SIGNED_IN, lastSync: new Date(), email: "foo@example.com" });
     await showMenuPromise("appMenu");
     await showHighlightPromise("accountStatus");
     let highlight = document.getElementById("UITourHighlightContainer");
     let expectedTarget = "appMenu-fxa-avatar";
-    is(highlight.popupBoxObject.anchorNode.id, expectedTarget, "Anchored on avatar");
+    is(highlight.anchorNode.id, expectedTarget, "Anchored on avatar");
     is(highlight.getAttribute("targetName"), "accountStatus", "Correct highlight target");
   }),
 ];
 
 function signOut() {
   // we always want a "localOnly" signout here...
   return fxAccounts.signOut(true);
 }
--- a/browser/components/uitour/test/browser_trackingProtection_tour.js
+++ b/browser/components/uitour/test/browser_trackingProtection_tour.js
@@ -67,17 +67,17 @@ async function checkToggleTarget(targetI
     is(available, expectedAvailable, "Target has expected availability.");
   };
   await testTargetAvailability(false);
   await showMenuPromise("controlCenter");
   await testTargetAvailability(true);
 
   await showInfoPromise(targetID, "This is " + targetID,
                         "My arrow should be on the side");
-  is(popup.popupBoxObject.alignmentPosition, "end_before",
+  is(popup.alignmentPosition, "end_before",
      "Check " + targetID + " position");
 
   let hideMenuPromise =
         promisePanelElementHidden(window, gIdentityHandler._identityPopup);
   await gContentAPI.hideMenu("controlCenter");
   await hideMenuPromise;
 
   ok(!is_visible(popup), "The tooltip should now be hidden.");
--- a/browser/components/uitour/test/head.js
+++ b/browser/components/uitour/test/head.js
@@ -113,17 +113,17 @@ function elementVisiblePromise(element, 
   return waitForConditionPromise(() => is_visible(element), "Timeout waiting for visibility: " + msg);
 }
 
 function elementHiddenPromise(element, msg) {
   return waitForConditionPromise(() => is_hidden(element), "Timeout waiting for invisibility: " + msg);
 }
 
 function waitForPopupAtAnchor(popup, anchorNode, nextTestFn, msg) {
-  waitForCondition(() => is_visible(popup) && popup.popupBoxObject.anchorNode == anchorNode,
+  waitForCondition(() => is_visible(popup) && popup.anchorNode == anchorNode,
                    () => {
                      ok(true, msg);
                      is_element_visible(popup, "Popup should be visible");
                      nextTestFn();
                    },
                    "Timeout waiting for popup at anchor: " + msg);
 }
 
--- a/browser/extensions/activity-stream/lib/PlacesFeed.jsm
+++ b/browser/extensions/activity-stream/lib/PlacesFeed.jsm
@@ -17,17 +17,17 @@ const LINK_BLOCKED_EVENT = "newtab-linkB
 const PLACES_LINKS_CHANGED_DELAY_TIME = 1000; // time in ms to delay timer for places links changed events
 
 /**
  * Observer - a wrapper around history/bookmark observers to add the QueryInterface.
  */
 class Observer {
   constructor(dispatch, observerInterface) {
     this.dispatch = dispatch;
-    this.QueryInterface = XPCOMUtils.generateQI([observerInterface, Ci.nsISupportsWeakReference]);
+    this.QueryInterface = ChromeUtils.generateQI([observerInterface, Ci.nsISupportsWeakReference]);
   }
 }
 
 /**
  * HistoryObserver - observes events from PlacesUtils.history
  */
 class HistoryObserver extends Observer {
   constructor(dispatch) {
--- a/browser/extensions/followonsearch/content/followonsearch-fs.js
+++ b/browser/extensions/followonsearch/content/followonsearch-fs.js
@@ -136,17 +136,17 @@ gLastSearchQueue.push = function(...args
 // that started from Firefox
 let searchingGoogle = false;
 
 /**
  * Since most codes are in the URL, we can handle them via
  * a progress listener.
  */
 var webProgressListener = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
   onLocationChange(aWebProgress, aRequest, aLocation, aFlags)
   {
     if (aWebProgress.DOMWindow && (aWebProgress.DOMWindow != content)) {
       return;
     }
     try {
       if (!aWebProgress.isTopLevel ||
           // Not a URL
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -76,17 +76,17 @@ AutocompleteFactory.prototype = {
  */
 function AutofillProfileAutoCompleteSearch() {
   FormAutofillUtils.defineLazyLogGetter(this, "AutofillProfileAutoCompleteSearch");
 }
 AutofillProfileAutoCompleteSearch.prototype = {
   classID: Components.ID("4f9f1e4c-7f2c-439e-9c9e-566b68bc187d"),
   contractID: "@mozilla.org/autocomplete/search;1?name=autofill-profiles",
   classDescription: "AutofillProfileAutoCompleteSearch",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteSearch]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIAutoCompleteSearch]),
 
   // Begin nsIAutoCompleteSearch implementation
 
   /**
    * Searches for a given string and notifies a listener (either synchronously
    * or asynchronously) of the result
    *
    * @param {string} searchString the string to search for
@@ -204,17 +204,17 @@ AutofillProfileAutoCompleteSearch.protot
       });
 
       Services.cpmm.sendAsyncMessage("FormAutofill:GetRecords", data);
     });
   },
 };
 
 let ProfileAutocomplete = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
   lastProfileAutoCompleteResult: null,
   lastProfileAutoCompleteFocusedInput: null,
   _registered: false,
   _factory: null,
 
   ensureRegistered() {
     if (this._registered) {
@@ -319,17 +319,17 @@ let ProfileAutocomplete = {
 };
 
 /**
  * Handles content's interactions for the process.
  *
  * NOTE: Declares it by "var" to make it accessible in unit tests.
  */
 var FormAutofillContent = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIFormSubmitObserver]),
   /**
    * @type {WeakMap} mapping FormLike root HTML elements to FormAutofillHandler objects.
    */
   _formsDetails: new WeakMap(),
 
   /**
    * @type {Set} Set of the fields with usable values in any saved profile.
    */
--- a/browser/extensions/formautofill/FormAutofillParent.jsm
+++ b/browser/extensions/formautofill/FormAutofillParent.jsm
@@ -64,17 +64,17 @@ function FormAutofillParent() {
       this._updateSavedFieldNames();
     });
 
     return formAutofillStorage;
   });
 }
 
 FormAutofillParent.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
   /**
    * Cache of the Form Autofill status (considering preferences and storage).
    */
   _active: null,
 
   /**
    * The status of Form Autofill's initialization.
--- a/browser/extensions/formautofill/MasterPassword.jsm
+++ b/browser/extensions/formautofill/MasterPassword.jsm
@@ -172,17 +172,17 @@ var MasterPassword = {
     if (!this.isUIBusy) {
       log.debug("waitForExistingDialog: Dialog isn't showing. isLoggedIn:", this.isLoggedIn);
       return this.isLoggedIn;
     }
 
     return new Promise((resolve) => {
       log.debug("waitForExistingDialog: Observing the open dialog");
       let observer = {
-        QueryInterface: XPCOMUtils.generateQI([
+        QueryInterface: ChromeUtils.generateQI([
           Ci.nsIObserver,
           Ci.nsISupportsWeakReference,
         ]),
 
         observe(subject, topic, data) {
           log.debug("waitForExistingDialog: Got notification:", topic);
           // Only run observer once.
           Services.obs.removeObserver(this, "passwordmgr-crypto-login");
--- a/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
+++ b/browser/extensions/formautofill/ProfileAutoCompleteResult.jsm
@@ -21,17 +21,17 @@ class ProfileAutoCompleteResult {
   constructor(searchString, focusedFieldName, allFieldNames, matchingProfiles, {
     resultCode = null,
     isSecure = true,
     isInputAutofilled = false,
   }) {
     log.debug("Constructing new ProfileAutoCompleteResult:", [...arguments]);
 
     // nsISupports
-    this.QueryInterface = XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult]);
+    this.QueryInterface = ChromeUtils.generateQI([Ci.nsIAutoCompleteResult]);
 
     // The user's query string
     this.searchString = searchString;
     // The field name of the focused input.
     this._focusedFieldName = focusedFieldName;
     // The matching profiles contains the information for filling forms.
     this._matchingProfiles = matchingProfiles;
     // The default item that should be entered if none is selected
--- a/browser/extensions/formautofill/test/unit/test_masterPassword.js
+++ b/browser/extensions/formautofill/test/unit/test_masterPassword.js
@@ -41,24 +41,24 @@ let gMockPrompter = {
           "Please enter your master password.",
           "password prompt text should be as expected");
     equal(checkMsg, null, "checkMsg should be null");
     ok(this.passwordToTry, "passwordToTry should be non-null");
     password.value = this.passwordToTry;
     return true;
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPrompt]),
 };
 
 // Mock nsIWindowWatcher. PSM calls getNewPrompter on this to get an nsIPrompt
 // to call promptPassword. We return the mock one, above.
 let gWindowWatcher = {
   getNewPrompter: () => gMockPrompter,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWindowWatcher]),
 };
 
 // Ensure that the appropriate initialization has happened.
 do_get_profile();
 
 let windowWatcherCID =
   MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1",
                          gWindowWatcher);
--- a/browser/extensions/pdfjs/content/PdfJs.jsm
+++ b/browser/extensions/pdfjs/content/PdfJs.jsm
@@ -122,17 +122,17 @@ Factory.prototype = {
     if (this._classID2) {
       registrar.unregisterFactory(this._classID2, this._factory);
     }
     this._factory = null;
   },
 };
 
 var PdfJs = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
   _registered: false,
   _initialized: false,
 
   init: function init(remote) {
     if (Services.appinfo.processType !==
         Services.appinfo.PROCESS_TYPE_DEFAULT) {
       throw new Error("PdfJs.init should only get called " +
                       "in the parent process.");
--- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
+++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
@@ -804,22 +804,17 @@ PdfStreamConverter.prototype = {
   // properties required for XPCOM registration:
   classID: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2291}"),
   classDescription: "pdf.js Component",
   contractID: "@mozilla.org/streamconv;1?from=application/pdf&to=*/*",
 
   classID2: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2292}"),
   contractID2: "@mozilla.org/streamconv;1?from=application/pdf&to=text/html",
 
-  QueryInterface: XPCOMUtils.generateQI([
-      Ci.nsISupports,
-      Ci.nsIStreamConverter,
-      Ci.nsIStreamListener,
-      Ci.nsIRequestObserver
-  ]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIStreamConverter, Ci.nsIStreamListener, Ci.nsIRequestObserver]),
 
   /*
    * This component works as such:
    * 1. asyncConvertData stores the listener
    * 2. onStartRequest creates a new channel, streams the viewer
    * 3. If range requests are supported:
    *      3.1. Leave the request open until the viewer is ready to switch to
    *           range requests.
--- a/browser/extensions/pocket/content/AboutPocket.jsm
+++ b/browser/extensions/pocket/content/AboutPocket.jsm
@@ -26,17 +26,17 @@ function AboutPage(chromeURL, aboutHost,
   this.chromeURL = chromeURL;
   this.aboutHost = aboutHost;
   this.classID = Components.ID(classID);
   this.description = description;
   this.uriFlags = uriFlags;
 }
 
 AboutPage.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIAboutModule]),
   getURIFlags(aURI) { // eslint-disable-line no-unused-vars
     return this.uriFlags;
   },
 
   newChannel(aURI, aLoadInfo) {
     let newURI = Services.io.newURI(this.chromeURL);
     let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
                                                             aLoadInfo);
--- a/browser/extensions/webcompat-reporter/content/WebCompatReporter.jsm
+++ b/browser/extensions/webcompat-reporter/content/WebCompatReporter.jsm
@@ -103,17 +103,17 @@ let WebCompatReporter = {
       `${WebCompatReporter.endpoint}?${params}`,
       {inBackground: false, triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()});
 
     // If we successfully got a screenshot blob, add a listener to know when
     // the new tab is loaded before sending it over.
     if (tabData && tabData.blob) {
       let browser = gBrowser.getBrowserForTab(tab);
       let loadedListener = {
-        QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
+        QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
           "nsISupportsWeakReference"]),
         onStateChange(webProgress, request, flags, status) {
           let isStopped = flags & Ci.nsIWebProgressListener.STATE_STOP;
           let isNetwork = flags & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
           if (isStopped && isNetwork && webProgress.isTopLevel) {
             let location;
             try {
               location = request.QueryInterface(Ci.nsIChannel).URI;
--- a/browser/extensions/webcompat/bootstrap.js
+++ b/browser/extensions/webcompat/bootstrap.js
@@ -1,34 +1,45 @@
 /* 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/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const PREF_BRANCH = "extensions.webcompat.";
-const PREF_DEFAULTS = {perform_ua_overrides: true};
+const PREF_DEFAULTS = {
+  perform_injections: true,
+  perform_ua_overrides: true
+};
+
+const INJECTIONS_ENABLE_PREF_NAME = "extensions.webcompat.perform_injections";
+
+const BROWSER_STARTUP_FINISHED_TOPIC = "browser-delayed-startup-finished";
 
 const UA_OVERRIDES_INIT_TOPIC = "useragentoverrides-initialized";
 const UA_ENABLE_PREF_NAME = "extensions.webcompat.perform_ua_overrides";
 
 ChromeUtils.defineModuleGetter(this, "UAOverrider", "chrome://webcompat/content/lib/ua_overrider.jsm");
 ChromeUtils.defineModuleGetter(this, "UAOverrides", "chrome://webcompat/content/data/ua_overrides.jsm");
 
 let overrider;
+let webextensionPort;
+
+function InjectionsEnablePrefObserver() {
+  let isEnabled = Services.prefs.getBoolPref(INJECTIONS_ENABLE_PREF_NAME);
+  webextensionPort.postMessage({
+    type: "injection-pref-changed",
+    prefState: isEnabled
+  });
+}
 
 function UAEnablePrefObserver() {
   let isEnabled = Services.prefs.getBoolPref(UA_ENABLE_PREF_NAME);
-  if (isEnabled && !overrider) {
-    overrider = new UAOverrider(UAOverrides);
-    overrider.init();
-  } else if (!isEnabled && overrider) {
-    overrider = null;
-  }
+  overrider.setShouldOverride(isEnabled);
 }
 
 function setDefaultPrefs() {
   const branch = Services.prefs.getDefaultBranch(PREF_BRANCH);
   for (const [key, val] of Object.entries(PREF_DEFAULTS)) {
     // If someone beat us to setting a default, don't overwrite it.
     if (branch.getPrefType(key) !== branch.PREF_INVALID) {
       continue;
@@ -52,32 +63,55 @@ this.install = function() {};
 this.uninstall = function() {};
 
 this.startup = function({webExtension}) {
   setDefaultPrefs();
 
   // Intentionally reset the preference on every browser restart to avoid site
   // breakage by accidentally toggled preferences or by leaving it off after
   // debugging a site.
+  Services.prefs.clearUserPref(INJECTIONS_ENABLE_PREF_NAME);
+  Services.prefs.addObserver(INJECTIONS_ENABLE_PREF_NAME, InjectionsEnablePrefObserver);
+
   Services.prefs.clearUserPref(UA_ENABLE_PREF_NAME);
   Services.prefs.addObserver(UA_ENABLE_PREF_NAME, UAEnablePrefObserver);
 
   // Listen to the useragentoverrides-initialized notification we get and
   // initialize our overrider there. This is done to avoid slowing down the
   // apparent startup proces, since we avoid loading anything before the first
   // window is visible to the user. See bug 1371442 for details.
-  let startupWatcher = {
+  let uaStartupObserver = {
     observe(aSubject, aTopic, aData) {
       if (aTopic !== UA_OVERRIDES_INIT_TOPIC) {
         return;
       }
 
       Services.obs.removeObserver(this, UA_OVERRIDES_INIT_TOPIC);
       overrider = new UAOverrider(UAOverrides);
       overrider.init();
     }
   };
-  Services.obs.addObserver(startupWatcher, UA_OVERRIDES_INIT_TOPIC);
+  Services.obs.addObserver(uaStartupObserver, UA_OVERRIDES_INIT_TOPIC);
+
+  // Observe browser-delayed-startup-finished and only initialize our embedded
+  // WebExtension after that. Otherwise, we'd try to initialize as soon as the
+  // browser starts up, which adds a heavy startup penalty.
+  let appStartupObserver = {
+    observe(aSubject, aTopic, aData) {
+      webExtension.startup().then((api) => {
+        api.browser.runtime.onConnect.addListener((port) => {
+          webextensionPort = port;
+        });
+
+        return Promise.resolve();
+      }).catch((ex) => {
+        console.error(ex);
+      });
+      Services.obs.removeObserver(this, BROWSER_STARTUP_FINISHED_TOPIC);
+    }
+  };
+  Services.obs.addObserver(appStartupObserver, BROWSER_STARTUP_FINISHED_TOPIC);
 };
 
 this.shutdown = function() {
+  Services.prefs.removeObserver(INJECTIONS_ENABLE_PREF_NAME, InjectionsEnablePrefObserver);
   Services.prefs.removeObserver(UA_ENABLE_PREF_NAME, UAEnablePrefObserver);
 };
--- a/browser/extensions/webcompat/content/data/ua_overrides.jsm
+++ b/browser/extensions/webcompat/content/data/ua_overrides.jsm
@@ -1,60 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
- * This is an array of objects that specify user agent overrides. Each object
- * can have three attributes:
- *
- *   * `baseDomain`, required: The base domain that further checks and user
- *     agents override are applied to. This does not include subdomains.
- *   * `uriMatcher`: Function that gets the requested URI passed in the first
- *     argument and needs to return boolean whether or not the override should
- *     be applied. If not provided, the user agent override will be applied
- *     every time.
- *   * `uaTransformer`, required: Function that gets the original Firefox user
- *     agent passed as its first argument and needs to return a string that
- *     will be used as the the user agent for this URI.
- *
- * Examples:
- *
- * Gets applied for all requests to mozilla.org and subdomains:
+ * For detailed information on our policies, and a documention on this format
+ * and its possibilites, please check the Mozilla-Wiki at
  *
- * ```
- *   {
- *     baseDomain: "mozilla.org",
- *     uaTransformer: (originalUA) => `Ohai Mozilla, it's me, ${originalUA}`
- *   }
- * ```
- *
- * Applies to *.example.com/app/*:
- *
- * ```
- *   {
- *     baseDomain: "example.com",
- *     uriMatcher: (uri) => uri.includes("/app/"),
- *     uaTransformer: (originalUA) => originalUA.replace("Firefox", "Otherfox")
- *   }
- * ```
+ * https://wiki.mozilla.org/Compatibility/Go_Faster_Addon/Override_Policies_and_Workflows#User_Agent_overrides
  */
-
 const UAOverrides = [
 
   /*
    * This is a dummy override that applies a Chrome UA to a dummy site that
    * blocks all browsers but Chrome.
    *
    * This was only put in place to allow QA to test this system addon on an
    * actual site, since we were not able to find a proper override in time.
    */
   {
     baseDomain: "schub.io",
-    uriMatcher: (uri) => uri.includes("webcompat-ua-dummy.schub.io"),
+    applications: ["firefox", "fennec"],
+    uriMatcher: (uri) => uri.includes("webcompat-addon-testcases.schub.io"),
     uaTransformer: (originalUA) => {
       let prefix = originalUA.substr(0, originalUA.indexOf(")") + 1);
       return `${prefix} AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36`;
     }
   }
 ];
 
 var EXPORTED_SYMBOLS = ["UAOverrides"]; /* exported UAOverrides */
--- a/browser/extensions/webcompat/content/lib/ua_overrider.jsm
+++ b/browser/extensions/webcompat/content/lib/ua_overrider.jsm
@@ -1,43 +1,79 @@
 /* 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/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
+ChromeUtils.defineModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "UserAgentOverrides", "resource://gre/modules/UserAgentOverrides.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "eTLDService", "@mozilla.org/network/effective-tld-service;1", "nsIEffectiveTLDService");
 
 class UAOverrider {
   constructor(overrides) {
     this._overrides = {};
+    this._shouldOverride = true;
 
     this.initOverrides(overrides);
   }
 
   initOverrides(overrides) {
+    // on xpcshell tests, there is no impleentation for nsIXULAppInfo, so this
+    // might fail there. To have all of our test cases running at all times,
+    // assume they are on Desktop for now.
+    let currentApplication = "firefox";
+    try {
+      currentApplication = Services.appinfo.name.toLowerCase();
+    } catch (_) {}
+
     for (let override of overrides) {
+      // Firefox for Desktop is the default application for all overrides.
+      if (!override.applications) {
+        override.applications = ["firefox"];
+      }
+
+      // If the current application is not targeted by the override in question,
+      // we can skip adding the override to our checks entirely.
+      if (!override.applications.includes(currentApplication)) {
+        continue;
+      }
+
       if (!this._overrides[override.baseDomain]) {
         this._overrides[override.baseDomain] = [];
       }
 
       if (!override.uriMatcher) {
         override.uriMatcher = () => true;
       }
 
       this._overrides[override.baseDomain].push(override);
     }
   }
 
+  /**
+   * Used for disabling overrides when the pref has been flipped to false.
+   *
+   * Since we no longer use our own event handlers, we check this bool in our
+   * override callback and simply return early if we are not supposed to do
+   * anything.
+   */
+  setShouldOverride(newState) {
+    this._shouldOverride = newState;
+  }
+
   init() {
     UserAgentOverrides.addComplexOverride(this.overrideCallback.bind(this));
   }
 
   overrideCallback(channel, defaultUA) {
+    if (!this._shouldOverride) {
+      return false;
+    }
+
     let uaOverride = this.lookupUAOverride(channel.URI, defaultUA);
     if (uaOverride) {
       console.log("The user agent has been overridden for compatibility reasons.");
       return uaOverride;
     }
 
     return false;
   }
--- a/browser/extensions/webcompat/install.rdf.in
+++ b/browser/extensions/webcompat/install.rdf.in
@@ -5,28 +5,37 @@
 
 #filter substitution
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
 
   <Description about="urn:mozilla:install-manifest">
     <em:id>webcompat@mozilla.org</em:id>
-    <em:version>1.1</em:version>
+    <em:version>2.0</em:version>
     <em:type>2</em:type>
     <em:bootstrap>true</em:bootstrap>
     <em:multiprocessCompatible>true</em:multiprocessCompatible>
+    <em:hasEmbeddedWebExtension>true</em:hasEmbeddedWebExtension>
 
-    <!-- Target Application this extension can install into,
-        with minimum and maximum supported versions. -->
+    <!-- Firefox Desktop -->
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
         <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion>
       </Description>
     </em:targetApplication>
 
+    <!-- Firefox for Android -->
+    <em:targetApplication>
+      <Description>
+        <em:id>{aa3c5121-dab2-40e2-81ca-7ea25febc110}</em:id>
+        <em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
+        <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
     <!-- Front End MetaData -->
     <em:name>Web Compat</em:name>
     <em:description>Urgent post-release fixes for web compatibility.</em:description>
   </Description>
 </RDF>
--- a/browser/extensions/webcompat/moz.build
+++ b/browser/extensions/webcompat/moz.build
@@ -6,16 +6,29 @@
 
 DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
 DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION']
 
 FINAL_TARGET_FILES.features['webcompat@mozilla.org'] += [
   'bootstrap.js'
 ]
 
+FINAL_TARGET_FILES.features['webcompat@mozilla.org']['webextension'] += [
+  'webextension/background.js',
+  'webextension/manifest.json'
+]
+
+FINAL_TARGET_FILES.features['webcompat@mozilla.org']['webextension']['injections']['css'] += [
+  'webextension/injections/css/bug0000000-dummy-css-injection.css'
+]
+
+FINAL_TARGET_FILES.features['webcompat@mozilla.org']['webextension']['injections']['js'] += [
+  'webextension/injections/js/bug0000000-dummy-js-injection.js'
+]
+
 FINAL_TARGET_PP_FILES.features['webcompat@mozilla.org'] += [
   'install.rdf.in'
 ]
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 JAR_MANIFESTS += ['jar.mn']
 
 with Files('**'):
new file mode 100644
--- /dev/null
+++ b/browser/extensions/webcompat/webextension/background.js
@@ -0,0 +1,55 @@
+/**
+ * For detailed information on our policies, and a documention on this format
+ * and its possibilites, please check the Mozilla-Wiki at
+ *
+ * https://wiki.mozilla.org/Compatibility/Go_Faster_Addon/Override_Policies_and_Workflows#User_Agent_overrides
+ */
+const contentScripts = [
+  {
+    matches: ["*://webcompat-addon-testcases.schub.io/*"],
+    css: [{file: "injections/css/bug0000000-dummy-css-injection.css"}],
+    js: [{file: "injections/js/bug0000000-dummy-js-injection.js"}],
+    runAt: "document_start"
+  }
+];
+
+/* globals browser */
+
+let port = browser.runtime.connect();
+let registeredContentScripts = [];
+
+function registerContentScripts() {
+  contentScripts.forEach(async (contentScript) => {
+    try {
+      let handle = await browser.contentScripts.register(contentScript);
+      registeredContentScripts.push(handle);
+    } catch (ex) {
+      console.error("Registering WebCompat GoFaster content scripts failed: ", ex);
+    }
+  });
+}
+
+function unregisterContentScripts() {
+  registeredContentScripts.forEach((contentScript) => {
+    contentScript.unregister();
+  });
+}
+
+port.onMessage.addListener((message) => {
+  switch (message.type) {
+    case "injection-pref-changed":
+      if (message.prefState) {
+        registerContentScripts();
+      } else {
+        unregisterContentScripts();
+      }
+      break;
+  }
+});
+
+/**
+ * Note that we reset all preferences on extension startup, so the injections will
+ * never be disabled when this loads up. Because of that, we can simply register
+ * right away.
+ */
+registerContentScripts();
new file mode 100644
--- /dev/null
+++ b/browser/extensions/webcompat/webextension/injections/css/bug0000000-dummy-css-injection.css
@@ -0,0 +1,3 @@
+#css-injection.red {
+  background-color: #0f0;
+}
new file mode 100644
--- /dev/null
+++ b/browser/extensions/webcompat/webextension/injections/js/bug0000000-dummy-js-injection.js
@@ -0,0 +1,11 @@
+"use strict";
+
+/* globals exportFunction */
+
+Object.defineProperty(window.wrappedJSObject, "isTestFeatureSupported", {
+  get: exportFunction(function() {
+    return true;
+  }, window),
+
+  set: exportFunction(function() {}, window)
+});
new file mode 100644
--- /dev/null
+++ b/browser/extensions/webcompat/webextension/manifest.json
@@ -0,0 +1,23 @@
+{
+  "manifest_version": 2,
+  "name": "Web Compat",
+  "description": "Urgent post-release fixes for web compatibility.",
+  "version": "2.0",
+
+  "applications": {
+    "gecko": {
+      "id": "webcompat@mozilla.org",
+      "strict_min_version": "59.0b5"
+    }
+  },
+
+  "permissions": [
+    "<all_urls>"
+  ],
+
+  "background": {
+    "scripts": [
+      "background.js"
+    ]
+  }
+}
--- a/browser/modules/BrowserUsageTelemetry.jsm
+++ b/browser/modules/BrowserUsageTelemetry.jsm
@@ -222,18 +222,18 @@ let URICountListener = {
 
   /**
    * Reset the counts. This should be called when breaking a session in Telemetry.
    */
   reset() {
     this._domainSet.clear();
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                          Ci.nsISupportsWeakReference]),
 };
 
 let urlbarListener = {
 
   // This is needed for recordUrlbarSelectedResultMethod().
   selectedIndex: -1,
 
   init() {
@@ -307,18 +307,18 @@ let urlbarListener = {
               .getKeyedHistogramById("FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE")
               .add(actionType, idx);
     } else {
       Cu.reportError("Unknown FX_URLBAR_SELECTED_RESULT_TYPE type: " +
                      actionType);
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 };
 
 let BrowserUsageTelemetry = {
   _inited: false,
 
   init() {
     this._lastRecordTabCount = 0;
     urlbarListener.init();
@@ -336,18 +336,18 @@ let BrowserUsageTelemetry = {
     const counts = getOpenTabsAndWinsCounts();
     Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, counts.tabCount);
     Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount);
 
     // Reset the URI counter.
     URICountListener.reset();
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 
   uninit() {
     if (!this._inited) {
       return;
     }
     Services.obs.removeObserver(this, DOMWINDOW_OPENED_TOPIC);
     Services.obs.removeObserver(this, TELEMETRY_SUBSESSIONSPLIT_TOPIC);
     urlbarListener.uninit();
--- a/browser/modules/FormSubmitObserver.jsm
+++ b/browser/modules/FormSubmitObserver.jsm
@@ -222,10 +222,10 @@ FormSubmitObserver.prototype =
     if (this._content == null) {
       return true;
     }
     let target = aEvent.originalTarget;
     return (target == this._content.document ||
             (target.ownerDocument && target.ownerDocument == this._content.document));
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIFormSubmitObserver])
 };
--- a/browser/modules/Sanitizer.jsm
+++ b/browser/modules/Sanitizer.jsm
@@ -264,17 +264,17 @@ var Sanitizer = {
         if (this.shouldSanitizeOnShutdown) {
           let itemsToClear = getItemsToClearFromPrefBranch(Sanitizer.PREF_SHUTDOWN_BRANCH);
           addPendingSanitization("shutdown", itemsToClear, {});
         }
       }
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsiObserver,
     Ci.nsISupportsWeakReference
   ]),
 
   // When making any changes to the sanitize implementations here,
   // please check whether the changes are applicable to Android
   // (mobile/android/modules/Sanitizer.jsm) as well.
 
--- a/browser/modules/SiteDataManager.jsm
+++ b/browser/modules/SiteDataManager.jsm
@@ -106,17 +106,17 @@ var SiteDataManager = {
       // Needs to root the observer since cache service keeps only a weak reference.
       this._getCacheSizeObserver = {
         onNetworkCacheDiskConsumption: consumption => {
           resolve(consumption);
           this._getCacheSizePromise = null;
           this._getCacheSizeObserver = null;
         },
 
-        QueryInterface: XPCOMUtils.generateQI([
+        QueryInterface: ChromeUtils.generateQI([
           Ci.nsICacheStorageConsumptionObserver,
           Ci.nsISupportsWeakReference
         ])
       };
 
       try {
         Services.cache2.asyncGetDiskConsumption(this._getCacheSizeObserver);
       } catch (e) {
--- a/browser/modules/WindowsPreviewPerTab.jsm
+++ b/browser/modules/WindowsPreviewPerTab.jsm
@@ -150,17 +150,17 @@ function PreviewController(win, tab) {
   XPCOMUtils.defineLazyGetter(this, "canvasPreview", function() {
     let canvas = PageThumbs.createCanvas();
     canvas.mozOpaque = true;
     return canvas;
   });
 }
 
 PreviewController.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITaskbarPreviewController]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsITaskbarPreviewController]),
 
   destroy() {
     this.tab.removeEventListener("TabAttrModified", this);
 
     // Break cycles, otherwise we end up leaking the window with everything
     // attached to it.
     delete this.win;
     delete this.preview;
@@ -830,17 +830,17 @@ var AeroPeek = {
           if (tab.getAttribute("image") == newValue) {
             win.onLinkIconAvailable(tab.linkedBrowser, newValue);
           }
         }
       }
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsISupportsWeakReference,
     Ci.nsINavHistoryObserver,
     Ci.nsIObserver
   ]),
 };
 
 XPCOMUtils.defineLazyGetter(AeroPeek, "cacheTimer", () =>
   Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
--- a/browser/modules/test/browser/browser_UsageTelemetry_domains.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_domains.js
@@ -26,17 +26,17 @@ function browserLocationChanged(browser)
       onStatusChange() {},
       onLocationChange(aWebProgress, aRequest, aURI, aFlags) {
         if (!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE)) {
           browser.webProgress.removeProgressListener(filter);
           filter.removeProgressListener(wpl);
           resolve();
         }
       },
-      QueryInterface: XPCOMUtils.generateQI([
+      QueryInterface: ChromeUtils.generateQI([
         Ci.nsIWebProgressListener,
         Ci.nsIWebProgressListener2,
       ]),
     };
     const filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
                      .createInstance(Ci.nsIWebProgress);
     filter.addProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL);
     browser.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
--- a/browser/modules/test/browser/contentSearch.js
+++ b/browser/modules/test/browser/contentSearch.js
@@ -64,17 +64,17 @@ function waitForLoadAndStopIt(expectedUR
           if ((flags & docStart) && webProg.isTopLevel && url == expectedURL) {
             webProgress.removeProgressListener(webProgressListener);
             webProgressListener = null;
             req.cancel(Cr.NS_ERROR_FAILURE);
             resolve(url);
           }
         }
       },
-      QueryInterface: XPCOMUtils.generateQI([
+      QueryInterface: ChromeUtils.generateQI([
         Ci.nsIWebProgressListener,
         Ci.nsISupportsWeakReference,
       ]),
     };
     webProgress.addProgressListener(webProgressListener, Ci.nsIWebProgress.NOTIFY_ALL);
     dump("waitForLoadAndStopIt: Waiting for URL to load: " + expectedURL + "\n");
   });
 }
--- a/browser/modules/test/browser/formValidation/browser_form_validation.js
+++ b/browser/modules/test/browser/formValidation/browser_form_validation.js
@@ -44,17 +44,17 @@ function checkPopupShow() {
 }
 
 function checkPopupHide() {
   ok(gInvalidFormPopup.state != "showing" && gInvalidFormPopup.state != "open",
      "[Test " + testId + "] The invalid form popup should not be shown");
 }
 
 var gObserver = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIFormSubmitObserver]),
 
   notifyInvalidSubmit(aFormElement, aInvalidElements) {
   }
 };
 
 var testId = 0;
 
 function incrementTest() {
--- a/browser/modules/test/browser/head.js
+++ b/browser/modules/test/browser/head.js
@@ -165,33 +165,33 @@ function checkEvents(events, expectedEve
  * @param browser (<xul:browser>)
  *        The browser that we'll create a nsIContentPermissionRequest
  *        for.
  * @returns A nsIContentPermissionRequest-ish object.
  */
 function makeMockPermissionRequest(browser) {
   let type = {
     options: [],
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionType]),
   };
   let types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
   types.appendElement(type);
   let result = {
     types,
     principal: browser.contentPrincipal,
     requester: null,
     _cancelled: false,
     cancel() {
       this._cancelled = true;
     },
     _allowed: false,
     allow() {
       this._allowed = true;
     },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionRequest]),
   };
 
   // In the e10s-case, nsIContentPermissionRequest will have
   // element defined. window is defined otherwise.
   if (browser.isRemoteBrowser) {
     result.element = browser;
   } else {
     result.window = browser.contentWindow;
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -49,16 +49,17 @@ MACH_MODULES = [
     'taskcluster/mach_commands.py',
     'testing/awsy/mach_commands.py',
     'testing/firefox-ui/mach_commands.py',
     'testing/geckodriver/mach_commands.py',
     'testing/mach_commands.py',
     'testing/marionette/mach_commands.py',
     'testing/mochitest/mach_commands.py',
     'testing/mozharness/mach_commands.py',
+    'testing/raptor/mach_commands.py',
     'testing/talos/mach_commands.py',
     'testing/web-platform/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
     'tools/compare-locales/mach_commands.py',
     'tools/docs/mach_commands.py',
     'tools/lint/mach_commands.py',
     'tools/mach_commands.py',
     'tools/power/mach_commands.py',
--- a/chrome/test/unit/test_no_remote_registration.js
+++ b/chrome/test/unit/test_no_remote_registration.js
@@ -29,17 +29,17 @@ ProtocolHandler.prototype =
       mutator.setSpec(aBaseURI.resolve(aSpec));
     } else {
       mutator.setSpec(aSpec);
     }
     return mutator.finalize();
   },
   newChannel2() { throw Cr.NS_ERROR_NOT_IMPLEMENTED; },
   newChannel() { throw Cr.NS_ERROR_NOT_IMPLEMENTED; },
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIProtocolHandler
   ])
 };
 
 var testProtocols = [
   // It doesn't matter if it has this flag - the only flag we accept is
   // URI_IS_LOCAL_RESOURCE.
   {scheme: "moz-protocol-ui-resource",
--- a/devtools/client/definitions.js
+++ b/devtools/client/definitions.js
@@ -96,17 +96,24 @@ Tools.inspector = {
     return new InspectorPanel(iframeWindow, toolbox);
   }
 };
 Tools.webConsole = {
   id: "webconsole",
   accesskey: l10n("webConsoleCmd.accesskey"),
   ordinal: 2,
   url: "chrome://devtools/content/webconsole/webconsole.html",
-  browserConsoleURL: "chrome://devtools/content/webconsole/browserconsole.xul",
+  get browserConsoleUsesHTML() {
+    return Services.prefs.getBoolPref("devtools.browserconsole.html");
+  },
+  get browserConsoleURL() {
+    return this.browserConsoleUsesHTML ?
+      "chrome://devtools/content/webconsole/webconsole.html" :
+      "chrome://devtools/content/webconsole/browserconsole.xul";
+  },
   icon: "chrome://devtools/skin/images/tool-webconsole.svg",
   label: l10n("ToolboxTabWebconsole.label"),
   menuLabel: l10n("MenuWebconsole.label"),
   panelLabel: l10n("ToolboxWebConsole.panelLabel"),
   get tooltip() {
     return l10n("ToolboxWebconsole.tooltip2",
     (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
     l10n("webconsole.commandkey"));
--- a/devtools/client/framework/components/toolbox-controller.js
+++ b/devtools/client/framework/components/toolbox-controller.js
@@ -17,16 +17,17 @@ class ToolboxController extends Componen
   constructor(props, context) {
     super(props, context);
 
     // See the ToolboxToolbar propTypes for documentation on each of these items in
     // state, and for the definitions of the props that are expected to be passed in.
     this.state = {
       focusedButton: ELEMENT_PICKER_ID,
       toolboxButtons: [],
+      visibleToolboxButtonCount: 0,
       currentToolId: null,
       highlightedTools: new Set(),
       panelDefinitions: [],
       hostTypes: [],
       currentHostType: undefined,
       areDockOptionsEnabled: true,
       canCloseToolbox: true,
       isSplitConsoleActive: false,
@@ -167,17 +168,20 @@ class ToolboxController extends Componen
     // Listen for updates of the checked attribute.
     this.state.toolboxButtons.forEach(button => {
       button.off("updatechecked", this.state.checkedButtonsUpdated);
     });
     toolboxButtons.forEach(button => {
       button.on("updatechecked", this.state.checkedButtonsUpdated);
     });
 
-    this.setState({ toolboxButtons }, this.updateButtonIds);
+    const visibleToolboxButtonCount =
+      toolboxButtons.filter(button => button.isVisible).length;
+
+    this.setState({ toolboxButtons, visibleToolboxButtonCount }, this.updateButtonIds);
   }
 
   render() {
     return ToolboxToolbar(Object.assign({}, this.props, this.state));
   }
 }
 
 module.exports = ToolboxController;
--- a/devtools/client/framework/components/toolbox-tabs.js
+++ b/devtools/client/framework/components/toolbox-tabs.js
@@ -23,16 +23,17 @@ class ToolboxTabs extends Component {
     return {
       currentToolId: PropTypes.string,
       focusButton: PropTypes.func,
       focusedButton: PropTypes.string,
       highlightedTools: PropTypes.object,
       panelDefinitions: PropTypes.array,
       selectTool: PropTypes.func,
       toolbox: PropTypes.object,
+      visibleToolboxButtonCount: PropTypes.number.isRequired,
       L10N: PropTypes.object,
       onTabsOrderUpdated: PropTypes.func.isRequired,
     };
   }
 
   constructor(props) {
     super(props);
 
@@ -89,17 +90,18 @@ class ToolboxTabs extends Component {
     // For example, the case of changing the tab's order.
     return prevPanels.join("-") === nextPanels.join("-");
   }
 
   /**
    * Return true if we should update the overflowed tabs.
    */
   shouldUpdateToolboxTabs(prevProps, nextProps) {
-    if (prevProps.currentToolId !== nextProps.currentToolId) {
+    if (prevProps.currentToolId !== nextProps.currentToolId ||
+        prevProps.visibleToolboxButtonCount !== nextProps.visibleToolboxButtonCount) {
       return true;
     }
 
     let prevPanels = prevProps.panelDefinitions.map(def => def.id);
     let nextPanels = nextProps.panelDefinitions.map(def => def.id);
     return !this.equalToolIdArray(prevPanels, nextPanels);
   }
 
--- a/devtools/client/framework/components/toolbox-toolbar.js
+++ b/devtools/client/framework/components/toolbox-toolbar.js
@@ -71,16 +71,21 @@ class ToolboxToolbar extends Component {
       // it to render nicely.
       canRender: PropTypes.bool,
       // Localization interface.
       L10N: PropTypes.object,
       // The devtools toolbox
       toolbox: PropTypes.object,
       // Call back function to detect tabs order updated.
       onTabsOrderUpdated: PropTypes.func.isRequired,
+      // Count of visible toolbox buttons which is used by ToolboxTabs component to
+      // recognize that the visibility of toolbox buttons were changed. Because in the
+      // component we cannot compare the visibility since the button definition instance
+      // in toolboxButtons will be unchanged.
+      visibleToolboxButtonCount: PropTypes.number,
     };
   }
 
   /**
    * The render function is kept fairly short for maintainability. See the individual
    * render functions for how each of the sections is rendered.
    */
   render() {
--- a/devtools/client/framework/test/browser.ini
+++ b/devtools/client/framework/test/browser.ini
@@ -111,16 +111,17 @@ skip-if = e10s # Bug 1069044 - destroyIn
 [browser_toolbox_telemetry_exit.js]
 [browser_toolbox_textbox_context_menu.js]
 [browser_toolbox_theme.js]
 [browser_toolbox_theme_registration.js]
 [browser_toolbox_toggle.js]
 [browser_toolbox_tool_ready.js]
 [browser_toolbox_tool_remote_reopen.js]
 [browser_toolbox_toolbar_overflow.js]
+[browser_toolbox_toolbar_overflow_button_visibility.js]
 [browser_toolbox_toolbar_reorder_by_dnd.js]
 [browser_toolbox_toolbar_reorder_by_width.js]
 [browser_toolbox_toolbar_reorder_with_extension.js]
 [browser_toolbox_tools_per_toolbox_registration.js]
 [browser_toolbox_view_source_01.js]
 [browser_toolbox_view_source_02.js]
 [browser_toolbox_view_source_03.js]
 [browser_toolbox_view_source_04.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/browser_toolbox_toolbar_overflow_button_visibility.js
@@ -0,0 +1,58 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for the toolbox tabs rearrangement when the visibility of toolbox buttons were changed.
+
+const { Toolbox } = require("devtools/client/framework/toolbox");
+
+add_task(async function() {
+  const tab = await addTab("about:blank");
+  const toolbox = await openToolboxForTab(tab, "options", Toolbox.HostType.BOTTOM);
+  const toolboxButtonPreferences =
+    toolbox.toolbarButtons.map(button => button.visibilityswitch);
+
+  const win = getWindow(toolbox);
+  const { outerWidth: originalWindowWidth, outerHeight: originalWindowHeight } = win;
+  registerCleanupFunction(() => {
+    for (const preference of toolboxButtonPreferences) {
+      Services.prefs.clearUserPref(preference);
+    }
+
+    win.resizeTo(originalWindowWidth, originalWindowHeight);
+  });
+
+  const optionsTool = toolbox.getCurrentPanel();
+  const checkButtons =
+    optionsTool.panelWin.document
+               .querySelectorAll("#enabled-toolbox-buttons-box input[type=checkbox]");
+
+  info("Test the count of shown devtools tab after making all buttons to be visible");
+  await resizeWindow(toolbox, 800);
+  // Once, make all toolbox button to be invisible.
+  setToolboxButtonsVisibility(checkButtons, false);
+  // Get count of shown devtools tab elements.
+  const initialTabCount = toolbox.doc.querySelectorAll(".devtools-tab").length;
+  // Make all toolbox button to be visible.
+  setToolboxButtonsVisibility(checkButtons, true);
+  ok(toolbox.doc.querySelectorAll(".devtools-tab").length < initialTabCount,
+     "Count of shown devtools tab should decreased");
+
+  info("Test the count of shown devtools tab after making all buttons to be invisible");
+  setToolboxButtonsVisibility(checkButtons, false);
+  is(toolbox.doc.querySelectorAll(".devtools-tab").length, initialTabCount,
+     "Count of shown devtools tab should be same to 1st count");
+});
+
+function setToolboxButtonsVisibility(checkButtons, doVisible) {
+  for (const checkButton of checkButtons) {
+    if (checkButton.checked === doVisible) {
+      continue;
+    }
+
+    checkButton.click();
+  }
+}
--- a/devtools/client/inspector/animation/actions/animations.js
+++ b/devtools/client/inspector/animation/actions/animations.js
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
   UPDATE_ANIMATIONS,
   UPDATE_DETAIL_VISIBILITY,
   UPDATE_ELEMENT_PICKER_ENABLED,
+  UPDATE_HIGHLIGHTED_NODE,
   UPDATE_SELECTED_ANIMATION,
   UPDATE_SIDEBAR_SIZE
 } = require("./index");
 
 module.exports = {
   /**
    * Update the list of animation in the animation inspector.
    */
@@ -39,16 +40,26 @@ module.exports = {
   updateElementPickerEnabled(elementPickerEnabled) {
     return {
       type: UPDATE_ELEMENT_PICKER_ENABLED,
       elementPickerEnabled,
     };
   },
 
   /**
+   * Update the highlighted node.
+   */
+  updateHighlightedNode(nodeFront) {
+    return {
+      type: UPDATE_HIGHLIGHTED_NODE,
+      highlightedNode: nodeFront ? nodeFront.actorID : null,
+    };
+  },
+
+  /**
    * Update selected animation.
    */
   updateSelectedAnimation(selectedAnimation) {
     return {
       type: UPDATE_SELECTED_ANIMATION,
       selectedAnimation,
     };
   },
--- a/devtools/client/inspector/animation/actions/index.js
+++ b/devtools/client/inspector/animation/actions/index.js
@@ -12,15 +12,18 @@ createEnum([
   "UPDATE_ANIMATIONS",
 
   // Update visibility of detail pane.
   "UPDATE_DETAIL_VISIBILITY",
 
   // Update state of the picker enabled.
   "UPDATE_ELEMENT_PICKER_ENABLED",
 
+  // Update highlighted node.
+  "UPDATE_HIGHLIGHTED_NODE",
+
   // Update selected animation.
   "UPDATE_SELECTED_ANIMATION",
 
   // Update sidebar size.
   "UPDATE_SIDEBAR_SIZE",
 
 ], module.exports);
--- a/devtools/client/inspector/animation/animation.js
+++ b/devtools/client/inspector/animation/animation.js
@@ -12,16 +12,17 @@ const EventEmitter = require("devtools/s
 
 const App = createFactory(require("./components/App"));
 const CurrentTimeTimer = require("./current-time-timer");
 
 const {
   updateAnimations,
   updateDetailVisibility,
   updateElementPickerEnabled,
+  updateHighlightedNode,
   updateSelectedAnimation,
   updateSidebarSize
 } = require("./actions/animations");
 const {
   isAllAnimationEqual,
   hasAnimationIterationCountInfinite,
   hasRunningAnimation,
 } = require("./utils/utils");
@@ -40,16 +41,18 @@ class AnimationInspector {
     this.removeAnimationsCurrentTimeListener =
       this.removeAnimationsCurrentTimeListener.bind(this);
     this.rewindAnimationsCurrentTime = this.rewindAnimationsCurrentTime.bind(this);
     this.selectAnimation = this.selectAnimation.bind(this);
     this.setAnimationsCurrentTime = this.setAnimationsCurrentTime.bind(this);
     this.setAnimationsPlaybackRate = this.setAnimationsPlaybackRate.bind(this);
     this.setAnimationsPlayState = this.setAnimationsPlayState.bind(this);
     this.setDetailVisibility = this.setDetailVisibility.bind(this);
+    this.setHighlightedNode = this.setHighlightedNode.bind(this);
+    this.setSelectedNode = this.setSelectedNode.bind(this);
     this.simulateAnimation = this.simulateAnimation.bind(this);
     this.simulateAnimationForKeyframesProgressBar =
       this.simulateAnimationForKeyframesProgressBar.bind(this);
     this.toggleElementPicker = this.toggleElementPicker.bind(this);
     this.update = this.update.bind(this);
     this.onAnimationStateChanged = this.onAnimationStateChanged.bind(this);
     this.onAnimationsCurrentTimeUpdated = this.onAnimationsCurrentTimeUpdated.bind(this);
     this.onAnimationsMutation = this.onAnimationsMutation.bind(this);
@@ -62,17 +65,16 @@ class AnimationInspector {
     EventEmitter.decorate(this);
     this.emit = this.emit.bind(this);
 
     this.init();
   }
 
   init() {
     const {
-      setSelectedNode,
       onShowBoxModelHighlighterForNode,
     } = this.inspector.getCommonComponentProps();
 
     const {
       onHideBoxModelHighlighter,
     } = this.inspector.getPanel("boxmodel").getComponentProps();
 
     const {
@@ -85,16 +87,18 @@ class AnimationInspector {
       isAnimationsRunning,
       removeAnimationsCurrentTimeListener,
       rewindAnimationsCurrentTime,
       selectAnimation,
       setAnimationsCurrentTime,
       setAnimationsPlaybackRate,
       setAnimationsPlayState,
       setDetailVisibility,
+      setHighlightedNode,
+      setSelectedNode,
       simulateAnimation,
       simulateAnimationForKeyframesProgressBar,
       toggleElementPicker,
     } = this;
 
     const target = this.inspector.target;
     this.animationsFront = new AnimationsFront(target.client, target.form);
 
@@ -120,16 +124,17 @@ class AnimationInspector {
           onShowBoxModelHighlighterForNode,
           removeAnimationsCurrentTimeListener,
           rewindAnimationsCurrentTime,
           selectAnimation,
           setAnimationsCurrentTime,
           setAnimationsPlaybackRate,
           setAnimationsPlayState,
           setDetailVisibility,
+          setHighlightedNode,
           setSelectedNode,
           simulateAnimation,
           simulateAnimationForKeyframesProgressBar,
           toggleElementPicker,
         }
       )
     );
     this.provider = provider;
@@ -344,16 +349,26 @@ class AnimationInspector {
   async rewindAnimationsCurrentTime() {
     await this.setAnimationsCurrentTime(0, true);
   }
 
   selectAnimation(animation) {
     this.inspector.store.dispatch(updateSelectedAnimation(animation));
   }
 
+  async setSelectedNode(nodeFront) {
+    if (this.inspector.selection.nodeFront === nodeFront) {
+      return;
+    }
+
+    await this.inspector.getCommonComponentProps()
+              .setSelectedNode(nodeFront, { reason: "animation-panel" });
+    await nodeFront.scrollIntoView();
+  }
+
   async setAnimationsCurrentTime(currentTime, shouldRefresh) {
     this.stopAnimationsCurrentTimeTimer();
     this.onAnimationsCurrentTimeUpdated(currentTime);
 
     if (!shouldRefresh && this.isCurrentTimeSet) {
       return;
     }
 
@@ -437,16 +452,32 @@ class AnimationInspector {
     }
   }
 
   setDetailVisibility(isVisible) {
     this.inspector.store.dispatch(updateDetailVisibility(isVisible));
   }
 
   /**
+   * Highlight the given node with the box model highlighter.
+   * If no node is provided, hide the box model highlighter.
+   *
+   * @param {NodeFront} nodeFront
+   */
+  async setHighlightedNode(nodeFront) {
+    await this.inspector.highlighters.hideBoxModelHighlighter();
+
+    if (nodeFront) {
+      await this.inspector.highlighters.showBoxModelHighlighter(nodeFront);
+    }
+
+    this.inspector.store.dispatch(updateHighlightedNode(nodeFront));
+  }
+
+  /**
    * Returns simulatable animation by given parameters.
    * The returned animation is implementing Animation interface of Web Animation API.
    * https://drafts.csswg.org/web-animations/#the-animation-interface
    *
    * @param {Array} keyframes
    *        e.g. [{ opacity: 0 }, { opacity: 1 }]
    * @param {Object} effectTiming
    *        e.g. { duration: 1000, fill: "both" }
--- a/devtools/client/inspector/animation/components/AnimationItem.js
+++ b/devtools/client/inspector/animation/components/AnimationItem.js
@@ -18,16 +18,17 @@ class AnimationItem extends Component {
       animation: PropTypes.object.isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getAnimatedPropertyMap: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       selectAnimation: PropTypes.func.isRequired,
       selectedAnimation: PropTypes.object.isRequired,
+      setHighlightedNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       timeScale: PropTypes.object.isRequired,
     };
   }
 
   constructor(props) {
     super(props);
@@ -56,16 +57,17 @@ class AnimationItem extends Component {
     const {
       animation,
       emitEventForTest,
       getAnimatedPropertyMap,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       selectAnimation,
+      setHighlightedNode,
       setSelectedNode,
       simulateAnimation,
       timeScale,
     } = this.props;
     const {
       isSelected,
     } = this.state;
 
@@ -76,16 +78,17 @@ class AnimationItem extends Component {
       },
       AnimationTarget(
         {
           animation,
           emitEventForTest,
           getNodeFromActor,
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
+          setHighlightedNode,
           setSelectedNode,
         }
       ),
       SummaryGraph(
         {
           animation,
           emitEventForTest,
           getAnimatedPropertyMap,
--- a/devtools/client/inspector/animation/components/AnimationList.js
+++ b/devtools/client/inspector/animation/components/AnimationList.js
@@ -15,31 +15,33 @@ class AnimationList extends PureComponen
     return {
       animations: PropTypes.arrayOf(PropTypes.object).isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getAnimatedPropertyMap: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       selectAnimation: PropTypes.func.isRequired,
+      setHighlightedNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       timeScale: PropTypes.object.isRequired,
     };
   }
 
   render() {
     const {
       animations,
       emitEventForTest,
       getAnimatedPropertyMap,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       selectAnimation,
+      setHighlightedNode,
       setSelectedNode,
       simulateAnimation,
       timeScale,
     } = this.props;
 
     return dom.ul(
       {
         className: "animation-list"
@@ -49,16 +51,17 @@ class AnimationList extends PureComponen
           {
             animation,
             emitEventForTest,
             getAnimatedPropertyMap,
             getNodeFromActor,
             onHideBoxModelHighlighter,
             onShowBoxModelHighlighterForNode,
             selectAnimation,
+            setHighlightedNode,
             setSelectedNode,
             simulateAnimation,
             timeScale,
           }
         )
       )
     );
   }
--- a/devtools/client/inspector/animation/components/AnimationListContainer.js
+++ b/devtools/client/inspector/animation/components/AnimationListContainer.js
@@ -20,16 +20,17 @@ class AnimationListContainer extends Pur
       emitEventForTest: PropTypes.func.isRequired,
       getAnimatedPropertyMap: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
       selectAnimation: PropTypes.func.isRequired,
       setAnimationsCurrentTime: PropTypes.func.isRequired,
+      setHighlightedNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       timeScale: PropTypes.object.isRequired,
     };
   }
 
   render() {
     const {
@@ -38,16 +39,17 @@ class AnimationListContainer extends Pur
       emitEventForTest,
       getAnimatedPropertyMap,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       removeAnimationsCurrentTimeListener,
       selectAnimation,
       setAnimationsCurrentTime,
+      setHighlightedNode,
       setSelectedNode,
       simulateAnimation,
       timeScale,
     } = this.props;
 
     return dom.div(
       {
         className: "animation-list-container"
@@ -64,16 +66,17 @@ class AnimationListContainer extends Pur
         {
           animations,
           emitEventForTest,
           getAnimatedPropertyMap,
           getNodeFromActor,
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
           selectAnimation,
+          setHighlightedNode,
           setSelectedNode,
           simulateAnimation,
           timeScale,
         }
       )
     );
   }
 }
--- a/devtools/client/inspector/animation/components/AnimationTarget.js
+++ b/devtools/client/inspector/animation/components/AnimationTarget.js
@@ -1,31 +1,36 @@
 /* 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 { Component } = require("devtools/client/shared/vendor/react");
+const { connect } = require("devtools/client/shared/vendor/react-redux");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { translateNodeFrontToGrip } = require("devtools/client/inspector/shared/utils");
 
 const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
 const { Rep } = REPS;
 const ElementNode = REPS.ElementNode;
 
+const { getInspectorStr } = require("../utils/l10n");
+
 class AnimationTarget extends Component {
   static get propTypes() {
     return {
       animation: PropTypes.object.isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
+      highlightedNode: PropTypes.string.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
+      setHighlightedNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
     };
   }
 
   constructor(props) {
     super(props);
 
     this.state = {
@@ -39,21 +44,22 @@ class AnimationTarget extends Component 
 
   componentWillReceiveProps(nextProps) {
     if (this.props.animation.actorID !== nextProps.animation.actorID) {
       this.updateNodeFront(nextProps.animation);
     }
   }
 
   shouldComponentUpdate(nextProps, nextState) {
-    return this.state.nodeFront !== nextState.nodeFront;
+    return this.state.nodeFront !== nextState.nodeFront ||
+           this.props.highlightedNode !== nextState.highlightedNode;
   }
 
   async updateNodeFront(animation) {
-    const { emitEventForTest, getNodeFromActor } = this.props;
+    const { getNodeFromActor } = this.props;
 
     // Try and get it from the playerFront directly.
     let nodeFront = animation.animationTargetNodeFront;
 
     // Next, get it from the walkerActor if it wasn't found.
     if (!nodeFront) {
       try {
         nodeFront = await getNodeFromActor(animation.actorID);
@@ -62,48 +68,65 @@ class AnimationTarget extends Component 
         // attributed to the panel having been destroyed in the meantime, this
         // error needs to be logged and render needs to stop.
         console.error(e);
         return;
       }
     }
 
     this.setState({ nodeFront });
-    emitEventForTest("animation-target-rendered");
   }
 
   render() {
     const {
+      emitEventForTest,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
+      highlightedNode,
+      setHighlightedNode,
       setSelectedNode,
     } = this.props;
 
     const { nodeFront } = this.state;
 
     if (!nodeFront) {
       return dom.div(
         {
           className: "animation-target"
         }
       );
     }
 
+    emitEventForTest("animation-target-rendered");
+
+    const isHighlighted = nodeFront.actorID === highlightedNode;
+
     return dom.div(
       {
-        className: "animation-target"
+        className: "animation-target" +
+                   (isHighlighted ? " highlighting" : ""),
       },
       Rep(
         {
           defaultRep: ElementNode,
           mode: MODE.TINY,
+          inspectIconTitle: getInspectorStr("inspector.nodePreview.highlightNodeLabel"),
           object: translateNodeFrontToGrip(nodeFront),
+          onDOMNodeClick: () => setSelectedNode(nodeFront),
           onDOMNodeMouseOut: () => onHideBoxModelHighlighter(),
           onDOMNodeMouseOver: () => onShowBoxModelHighlighterForNode(nodeFront),
-          onInspectIconClick: () => setSelectedNode(nodeFront,
-            { reason: "animation-panel" }),
+          onInspectIconClick: (_, e) => {
+            e.stopPropagation();
+            setHighlightedNode(isHighlighted ? null : nodeFront);
+          }
         }
       )
     );
   }
 }
 
-module.exports = AnimationTarget;
+const mapStateToProps = state => {
+  return {
+    highlightedNode: state.animations.highlightedNode,
+  };
+};
+
+module.exports = connect(mapStateToProps)(AnimationTarget);
--- a/devtools/client/inspector/animation/components/App.js
+++ b/devtools/client/inspector/animation/components/App.js
@@ -30,21 +30,23 @@ class App extends Component {
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
       rewindAnimationsCurrentTime: PropTypes.func.isRequired,
       selectAnimation: PropTypes.func.isRequired,
       setAnimationsCurrentTime: PropTypes.func.isRequired,
       setAnimationsPlaybackRate: PropTypes.func.isRequired,
       setAnimationsPlayState: PropTypes.func.isRequired,
       setDetailVisibility: PropTypes.func.isRequired,
+      setHighlightedNode: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       simulateAnimationForKeyframesProgressBar: PropTypes.func.isRequired,
       timeScale: PropTypes.object.isRequired,
       toggleElementPicker: PropTypes.func.isRequired,
+      toggleLockingHighlight: PropTypes.func.isRequired,
     };
   }
 
   shouldComponentUpdate(nextProps, nextState) {
     return this.props.animations.length !== 0 || nextProps.animations.length !== 0;
   }
 
   render() {
@@ -61,16 +63,17 @@ class App extends Component {
       onShowBoxModelHighlighterForNode,
       removeAnimationsCurrentTimeListener,
       rewindAnimationsCurrentTime,
       selectAnimation,
       setAnimationsCurrentTime,
       setAnimationsPlaybackRate,
       setAnimationsPlayState,
       setDetailVisibility,
+      setHighlightedNode,
       setSelectedNode,
       simulateAnimation,
       simulateAnimationForKeyframesProgressBar,
       timeScale,
       toggleElementPicker,
     } = this.props;
 
     return dom.div(
@@ -117,16 +120,17 @@ class App extends Component {
               emitEventForTest,
               getAnimatedPropertyMap,
               getNodeFromActor,
               onHideBoxModelHighlighter,
               onShowBoxModelHighlighterForNode,
               removeAnimationsCurrentTimeListener,
               selectAnimation,
               setAnimationsCurrentTime,
+              setHighlightedNode,
               setSelectedNode,
               simulateAnimation,
               timeScale,
             }
           ),
           vert: false,
         })
       ]
--- a/devtools/client/inspector/animation/reducers/animations.js
+++ b/devtools/client/inspector/animation/reducers/animations.js
@@ -3,26 +3,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
   UPDATE_ANIMATIONS,
   UPDATE_DETAIL_VISIBILITY,
   UPDATE_ELEMENT_PICKER_ENABLED,
+  UPDATE_HIGHLIGHTED_NODE,
   UPDATE_SELECTED_ANIMATION,
   UPDATE_SIDEBAR_SIZE,
 } = require("../actions/index");
 
 const TimeScale = require("../utils/timescale");
 
 const INITIAL_STATE = {
   animations: [],
   detailVisibility: false,
   elementPickerEnabled: false,
+  highlightedNode: null,
   selectedAnimation: null,
   sidebarSize: {
     height: 0,
     width: 0,
   },
   timeScale: null,
 };
 
@@ -52,16 +54,22 @@ const reducers = {
   },
 
   [UPDATE_ELEMENT_PICKER_ENABLED](state, { elementPickerEnabled }) {
     return Object.assign({}, state, {
       elementPickerEnabled
     });
   },
 
+  [UPDATE_HIGHLIGHTED_NODE](state, { highlightedNode }) {
+    return Object.assign({}, state, {
+      highlightedNode
+    });
+  },
+
   [UPDATE_SELECTED_ANIMATION](state, { selectedAnimation }) {
     const detailVisibility = !!selectedAnimation;
 
     return Object.assign({}, state, {
       detailVisibility,
       selectedAnimation
     });
   },
--- a/devtools/client/inspector/animation/test/browser.ini
+++ b/devtools/client/inspector/animation/test/browser.ini
@@ -19,16 +19,18 @@ support-files =
 [browser_animation_animated-property-list.js]
 [browser_animation_animated-property-list_unchanged-items.js]
 [browser_animation_animated-property-name.js]
 [browser_animation_animation-detail_close-button.js]
 [browser_animation_animation-detail_title.js]
 [browser_animation_animation-detail_visibility.js]
 [browser_animation_animation-list.js]
 [browser_animation_animation-target.js]
+[browser_animation_animation-target_highlight.js]
+[browser_animation_animation-target_select.js]
 [browser_animation_animation-timeline-tick.js]
 [browser_animation_current-time-label.js]
 [browser_animation_current-time-scrubber.js]
 [browser_animation_empty_on_invalid_nodes.js]
 [browser_animation_inspector_exists.js]
 [browser_animation_keyframes-graph_computed-value-path.js]
 [browser_animation_keyframes-graph_computed-value-path_easing-hint.js]
 [browser_animation_keyframes-graph_keyframe-marker.js]
--- a/devtools/client/inspector/animation/test/browser_animation_animation-target.js
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-target.js
@@ -2,34 +2,41 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test for following AnimationTarget component works.
 // * element existance
 // * number of elements
 // * content of element
+// * title of inspect icon
+
+const TEST_DATA = [
+  { expectedTextContent: "div.ball.animated" },
+  { expectedTextContent: "div.ball.long" },
+];
 
 add_task(async function() {
   await addTab(URL_ROOT + "doc_simple_animation.html");
   await removeAnimatedElementsExcept([".animated", ".long"]);
-  const { animationInspector, inspector, panel } = await openAnimationInspector();
+  const { animationInspector, panel } = await openAnimationInspector();
 
   info("Checking the animation target elements existance");
   const animationItemEls = panel.querySelectorAll(".animation-list .animation-item");
   is(animationItemEls.length, animationInspector.state.animations.length,
      "Number of animation target element should be same to number of animations " +
      "that displays");
 
-  for (const animationItemEl of animationItemEls) {
+  for (let i = 0; i < animationItemEls.length; i++) {
+    const animationItemEl = animationItemEls[i];
     const animationTargetEl = animationItemEl.querySelector(".animation-target");
     ok(animationTargetEl,
       "The animation target element should be in each animation item element");
+
+    info("Checking the content of animation target");
+    const testData = TEST_DATA[i];
+    is(animationTargetEl.textContent, testData.expectedTextContent,
+       "The target element's content is correct");
+    ok(animationTargetEl.querySelector(".objectBox"), "objectBox is in the page exists");
+    ok(animationTargetEl.querySelector(".open-inspector").title,
+       INSPECTOR_L10N.getStr("inspector.nodePreview.highlightNodeLabel"));
   }
-
-  info("Checking the content of animation target");
-  await selectNodeAndWaitForAnimations(".animated", inspector);
-  const animationTargetEl =
-    panel.querySelector(".animation-list .animation-item .animation-target");
-  is(animationTargetEl.textContent, "div.ball.animated",
-    "The target element's content is correct");
-  ok(animationTargetEl.querySelector(".objectBox"), "objectBox is in the page exists");
 });
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-target_highlight.js
@@ -0,0 +1,70 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for following highlighting related.
+// * highlight when mouse over on a target node
+// * unhighlight when mouse out from the above element
+// * lock highlighting when click on the inspect icon in animation target component
+// * add 'highlighting' class to animation target component during locking
+// * unlock highlighting when click on the above icon
+// * lock highlighting when click on the other inspect icon
+// * if the locked node has multi animations,
+//   the class will add to those animation target as well
+
+add_task(async function() {
+  await addTab(URL_ROOT + "doc_simple_animation.html");
+  await removeAnimatedElementsExcept([".animated", ".multi"]);
+  const { animationInspector, panel, toolbox } = await openAnimationInspector();
+
+  info("Check highlighting when mouse over on a target node");
+  let onHighlight = toolbox.once("node-highlight");
+  mouseOverOnTargetNode(animationInspector, panel, 0);
+  let nodeFront = await onHighlight;
+  assertNodeFront(nodeFront, "DIV", "ball animated");
+
+  info("Check unhighlighting when mouse out on a target node");
+  let onUnhighlight = toolbox.once("node-unhighlight");
+  mouseOutOnTargetNode(animationInspector, panel, 0);
+  await onUnhighlight;
+  ok(true, "Unhighlighted the targe node");
+
+  info("Check node is highlighted when the inspect icon is clicked");
+  onHighlight = toolbox.once("node-highlight");
+  await clickOnInspectIcon(animationInspector, panel, 0);
+  nodeFront = await onHighlight;
+  assertNodeFront(nodeFront, "DIV", "ball animated");
+  ok(panel.querySelectorAll(".animation-target")[0].classList.contains("highlighting"),
+    "The highlighted animation target element should have 'highlighting' class");
+
+  info("Check if the animation target is still highlighted on mouse out");
+  mouseOutOnTargetNode(animationInspector, panel, 0);
+  await wait(500);
+  ok(panel.querySelectorAll(".animation-target")[0].classList.contains("highlighting"),
+    "The highlighted element still should have 'highlighting' class");
+
+  info("Highlighting another animation target");
+  onHighlight = toolbox.once("node-highlight");
+  await clickOnInspectIcon(animationInspector, panel, 1);
+  nodeFront = await onHighlight;
+  assertNodeFront(nodeFront, "DIV", "ball multi");
+
+  info("Check the highlighted state of the animation targets");
+  const animationTargetEls = panel.querySelectorAll(".animation-target");
+  ok(!animationTargetEls[0].classList.contains("highlighting"),
+    "The animation target[0] should not have 'highlighting' class");
+  ok(animationTargetEls[1].classList.contains("highlighting"),
+    "The animation target[1] should have 'highlighting' class");
+  ok(animationTargetEls[2].classList.contains("highlighting"),
+    "The animation target[2] should have 'highlighting' class");
+});
+
+function assertNodeFront(nodeFront, tagName, classValue) {
+  is(nodeFront.tagName, "DIV",
+     "The highlighted node has the correct tagName");
+  is(nodeFront.attributes[0].name, "class",
+     "The highlighted node has the correct attributes");
+  is(nodeFront.attributes[0].value, classValue,
+     "The highlighted node has the correct class");
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-target_select.js
@@ -0,0 +1,32 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for following selection feature related AnimationTarget component works:
+// * select an animated node by clicking on target node
+// * select selected node by clicking on target node
+
+add_task(async function() {
+  await addTab(URL_ROOT + "doc_simple_animation.html");
+  await removeAnimatedElementsExcept([".multi", ".long"]);
+  const { animationInspector, panel } = await openAnimationInspector();
+
+  info("Check selecting an animated node by clicking on the target node");
+  await clickOnTargetNode(animationInspector, panel, 0);
+  is(panel.querySelectorAll(".animation-target").length, 2,
+     "The length of animations should be 2, because .multi node has two animations");
+
+  info("Check to avoid reselecting the already selected node");
+  let isUpdated = false;
+  const listener = () => {
+    isUpdated = true;
+  };
+  animationInspector.on("animation-target-rendered", listener);
+  const targetEl = panel.querySelectorAll(".animation-target .objectBox")[0];
+  targetEl.scrollIntoView(false);
+  EventUtils.synthesizeMouseAtCenter(targetEl, {}, targetEl.ownerGlobal);
+  await wait(500);
+  ok(!isUpdated, "Components should not have updated");
+  animationInspector.off("animation-target-rendered", listener);
+});
--- a/devtools/client/inspector/animation/test/head.js
+++ b/devtools/client/inspector/animation/test/head.js
@@ -93,97 +93,98 @@ addTab = async function(url) {
 const removeAnimatedElementsExcept = async function(selectors) {
   return executeInContent("Test:RemoveAnimatedElementsExcept", { selectors });
 };
 
 /**
  * Click on an animation in the timeline to select it.
  *
  * @param {AnimationInspector} animationInspector.
- * @param {AnimationsPanel} panel
- *        The panel instance.
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {Number} index
  *        The index of the animation to click on.
  */
 const clickOnAnimation = async function(animationInspector, panel, index) {
   info("Click on animation " + index + " in the timeline");
   const summaryGraphEl = panel.querySelectorAll(".animation-summary-graph")[index];
   await clickOnSummaryGraph(animationInspector, panel, summaryGraphEl);
 };
 
 /**
  * Click on an animation by given selector of node which is target element of animation.
  *
  * @param {AnimationInspector} animationInspector.
- * @param {AnimationsPanel} panel
- *        The panel instance.
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {String} selector
  *        Selector of node which is target element of animation.
  */
 const clickOnAnimationByTargetSelector = async function(animationInspector,
                                                         panel, selector) {
   info(`Click on animation whose selector of target element is '${ selector }'`);
   const animationItemEl = findAnimationItemElementsByTargetSelector(panel, selector);
   const summaryGraphEl = animationItemEl.querySelector(".animation-summary-graph");
   await clickOnSummaryGraph(animationInspector, panel, summaryGraphEl);
 };
 
 /**
  * Click on close button for animation detail pane.
  *
- * @param {AnimationsPanel} panel
- *        The panel instance.
+ * @param {DOMElement} panel
+ *        #animation-container element.
  */
 const clickOnDetailCloseButton = function(panel) {
   info("Click on close button for animation detail pane");
   const buttonEl = panel.querySelector(".animation-detail-close-button");
   const bounds = buttonEl.getBoundingClientRect();
   const x = bounds.width / 2;
   const y = bounds.height / 2;
   EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
 };
 
 /**
  * Click on pause/resume button.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
- *        The panel instance.
+ * @param {DOMElement} panel
+ *        #animation-container element.
  */
 const clickOnPauseResumeButton = async function(animationInspector, panel) {
   info("Click on pause/resume button");
   const buttonEl = panel.querySelector(".pause-resume-button");
   const bounds = buttonEl.getBoundingClientRect();
   const x = bounds.width / 2;
   const y = bounds.height / 2;
   EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
   await waitForSummaryAndDetail(animationInspector);
 };
 
 /**
  * Click on rewind button.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
- *        The panel instance.
+ * @param {DOMElement} panel
+ *        #animation-container element.
  */
 const clickOnRewindButton = async function(animationInspector, panel) {
   info("Click on rewind button");
   const buttonEl = panel.querySelector(".rewind-button");
   const bounds = buttonEl.getBoundingClientRect();
   const x = bounds.width / 2;
   const y = bounds.height / 2;
   EventUtils.synthesizeMouse(buttonEl, x, y, {}, buttonEl.ownerGlobal);
   await waitForSummaryAndDetail(animationInspector);
 };
 
 /**
  * Click on the scrubber controller pane to update the animation current time.
  *
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {Number} mouseDownPosition
  *        rate on scrubber controller pane.
  *        This method calculates
  *        `mouseDownPosition * offsetWidth + offsetLeft of scrubber controller pane`
  *        as the clientX of MouseEvent.
  */
 const clickOnCurrentTimeScrubberController = async function(animationInspector,
                                                             panel,
@@ -194,20 +195,40 @@ const clickOnCurrentTimeScrubberControll
   const mousedonwX = bounds.width * mouseDownPosition;
 
   info(`Click ${ mousedonwX } on scrubber controller`);
   EventUtils.synthesizeMouse(controllerEl, mousedonwX, 0, {}, controllerEl.ownerGlobal);
   await waitForSummaryAndDetail(animationInspector);
 };
 
 /**
+ * Click on the inspect icon for the given AnimationTargetComponent.
+ *
+ * @param {AnimationInspector} animationInspector.
+ * @param {DOMElement} panel
+ *        #animation-container element.
+ * @param {Number} index
+ *        The index of the AnimationTargetComponent to click on.
+ */
+const clickOnInspectIcon = async function(animationInspector, panel, index) {
+  info(`Click on an inspect icon in animation target component[${ index }]`);
+  const iconEl =
+    panel.querySelectorAll(".animation-target .objectBox .open-inspector")[index];
+  iconEl.scrollIntoView(false);
+  EventUtils.synthesizeMouseAtCenter(iconEl, {}, iconEl.ownerGlobal);
+  // We wait just one time, because the components are updated synchronously.
+  await animationInspector.once("animation-target-rendered");
+};
+
+/**
  * Click on playback rate selector to select given rate.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {Number} rate
  */
 const clickOnPlaybackRateSelector = async function(animationInspector, panel, rate) {
   info(`Click on playback rate selector to select ${rate}`);
   const selectEl = panel.querySelector(".playback-rate-selector");
   const optionEl = [...selectEl.options].filter(o => Number(o.value) === rate)[0];
 
   if (!optionEl) {
@@ -221,35 +242,56 @@ const clickOnPlaybackRateSelector = asyn
   EventUtils.synthesizeMouseAtCenter(optionEl, { type: "mouseup" }, win);
   await waitForSummaryAndDetail(animationInspector);
 };
 
 /**
  * Click on given summary graph element.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {Element} summaryGraphEl
  */
 const clickOnSummaryGraph = async function(animationInspector, panel, summaryGraphEl) {
   // Disable pointer-events of the scrubber in order to avoid to click accidently.
   const scrubberEl = panel.querySelector(".current-time-scrubber");
   scrubberEl.style.pointerEvents = "none";
   // Scroll to show the timeBlock since the element may be out of displayed area.
   summaryGraphEl.scrollIntoView(false);
   EventUtils.synthesizeMouseAtCenter(summaryGraphEl, {}, summaryGraphEl.ownerGlobal);
   await waitForAnimationDetail(animationInspector);
   // Restore the scrubber style.
   scrubberEl.style.pointerEvents = "unset";
 };
 
 /**
+ * Click on the target node for the given AnimationTargetComponent index.
+ *
+ * @param {AnimationInspector} animationInspector.
+ * @param {DOMElement} panel
+ *        #animation-container element.
+ * @param {Number} index
+ *        The index of the AnimationTargetComponent to click on.
+ */
+const clickOnTargetNode = async function(animationInspector, panel, index) {
+  info(`Click on a target node in animation target component[${ index }]`);
+  const targetEl = panel.querySelectorAll(".animation-target .objectBox")[index];
+  targetEl.scrollIntoView(false);
+  const onHighlight = animationInspector.inspector.toolbox.once("node-highlight");
+  EventUtils.synthesizeMouseAtCenter(targetEl, {}, targetEl.ownerGlobal);
+  await waitForRendering(animationInspector);
+  await onHighlight;
+};
+
+/**
  * Drag on the scrubber to update the animation current time.
  *
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {Number} mouseDownPosition
  *        rate on scrubber controller pane.
  *        This method calculates
  *        `mouseDownPosition * offsetWidth + offsetLeft of scrubber controller pane`
  *        as the clientX of MouseEvent.
  * @param {Number} mouseMovePosition
  *        Dispatch mousemove event with mouseMovePosition after mousedown.
  *        Calculation for clinetX is same to above.
@@ -275,17 +317,18 @@ const dragOnCurrentTimeScrubber = async 
   EventUtils.synthesizeMouse(controllerEl, mousemoveX, mouseYPixel,
                              { type: "mouseup" }, controllerEl.ownerGlobal);
   await waitForSummaryAndDetail(animationInspector);
 };
 
 /**
  * Drag on the scrubber controller pane to update the animation current time.
  *
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {Number} mouseDownPosition
  *        rate on scrubber controller pane.
  *        This method calculates
  *        `mouseDownPosition * offsetWidth + offsetLeft of scrubber controller pane`
  *        as the clientX of MouseEvent.
  * @param {Number} mouseMovePosition
  *        Dispatch mousemove event with mouseMovePosition after mousedown.
  *        Calculation for clinetX is same to above.
@@ -310,17 +353,18 @@ const dragOnCurrentTimeScrubberControlle
   await waitForSummaryAndDetail(animationInspector);
 };
 
 /**
  * Get current animation duration and rate of
  * clickOrDragOnCurrentTimeScrubberController in given pixels.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {Number} pixels
  * @return {Object}
  *         {
  *           duration,
  *           rate,
  *         }
  */
 const getDurationAndRate = function(animationInspector, panel, pixels) {
@@ -328,16 +372,48 @@ const getDurationAndRate = function(anim
   const bounds = controllerEl.getBoundingClientRect();
   const duration =
     animationInspector.state.timeScale.getDuration() / bounds.width * pixels;
   const rate = 1 / bounds.width * pixels;
   return { duration, rate };
 };
 
 /**
+ * Mouse over the target node for the given AnimationTargetComponent index.
+ *
+ * @param {AnimationInspector} animationInspector.
+ * @param {DOMElement} panel
+ *        #animation-container element.
+ * @param {Number} index
+ *        The index of the AnimationTargetComponent to click on.
+ */
+const mouseOverOnTargetNode = function(animationInspector, panel, index) {
+  info(`Mouse over on a target node in animation target component[${ index }]`);
+  const el = panel.querySelectorAll(".animation-target .objectBox")[index];
+  el.scrollIntoView(false);
+  EventUtils.synthesizeMouse(el, 10, 5, { type: "mouseover" }, el.ownerGlobal);
+};
+
+/**
+ * Mouse out of the target node for the given AnimationTargetComponent index.
+ *
+ * @param {AnimationInspector} animationInspector.
+ * @param {DOMElement} panel
+ *        #animation-container element.
+ * @param {Number} index
+ *        The index of the AnimationTargetComponent to click on.
+ */
+const mouseOutOnTargetNode = function(animationInspector, panel, index) {
+  info(`Mouse out on a target node in animation target component[${ index }]`);
+  const el = panel.querySelectorAll(".animation-target .objectBox")[index];
+  el.scrollIntoView(false);
+  EventUtils.synthesizeMouse(el, -1, -1, { type: "mouseout" }, el.ownerGlobal);
+};
+
+/**
  * Select animation inspector in sidebar and toolbar.
  *
  * @param {InspectorPanel} inspector
  */
 const selectAnimationInspector = async function(inspector) {
   await inspector.toolbox.selectTool("inspector");
   const onUpdated = inspector.once("inspector-updated");
   inspector.sidebar.select("newanimationinspector");
@@ -367,17 +443,18 @@ const selectNodeAndWaitForAnimations = a
   await onUpdated;
   await waitForRendering(inspector.animationinspector);
 };
 
 /**
  * Send keyboard event of space to given panel.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  */
 const sendSpaceKeyEvent = async function(animationInspector, panel) {
   panel.focus();
   EventUtils.sendKey("SPACE", panel.ownerGlobal);
   await waitForSummaryAndDetail(animationInspector);
 };
 
 /**
@@ -494,40 +571,43 @@ const waitForSummaryAndDetail = async fu
     waitForAnimationDetail(animationInspector),
   ]);
 };
 
 /**
  * Check whether current time of all animations and UI are given specified time.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {Number} time
  */
 function assertAnimationsCurrentTime(animationInspector, time) {
   const isTimeEqual =
     animationInspector.state.animations.every(({state}) => state.currentTime === time);
   ok(isTimeEqual, `Current time of animations should be ${ time }`);
 }
 
 /**
  * Check whether the animations are pausing.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  */
 function assertAnimationsPausing(animationInspector, panel) {
   assertAnimationsPausingOrRunning(animationInspector, panel, true);
 }
 
 /**
  * Check whether the animations are pausing/running.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  * @param {boolean} shouldPause
  */
 function assertAnimationsPausingOrRunning(animationInspector, panel, shouldPause) {
   const hasRunningAnimation =
     animationInspector.state.animations.some(({state}) => state.playState === "running");
 
   if (shouldPause) {
     is(hasRunningAnimation, false, "All animations should be paused");
@@ -535,17 +615,18 @@ function assertAnimationsPausingOrRunnin
     is(hasRunningAnimation, true, "Animations should be running at least one");
   }
 }
 
 /**
  * Check whether the animations are running.
  *
  * @param {AnimationInspector} animationInspector
- * @param {AnimationsPanel} panel
+ * @param {DOMElement} panel
+ *        #animation-container element.
  */
 function assertAnimationsRunning(animationInspector, panel) {
   assertAnimationsPausingOrRunning(animationInspector, panel, false);
 }
 
 /**
  * Check the <stop> element in the given linearGradientEl for the correct offset
  * and color attributes.
@@ -628,19 +709,22 @@ function isPassingThrough(pathSegList, x
   return false;
 }
 
 /**
  * Return animation item element by target node selector.
  * This function compares betweem animation-target textContent and given selector.
  * Then returns matched first item.
  *
- * @param {Element} panel - root element of animation inspector.
- * @param {String} selector - selector of tested element.
- * @return {Element} animation item element.
+ * @param {DOMElement} panel
+ *        #animation-container element.
+ * @param {String} selector
+ *        Selector of tested element.
+ * @return {DOMElement}
+ *        Animation item element.
  */
 function findAnimationItemElementsByTargetSelector(panel, selector) {
   const attrNameEls = panel.querySelectorAll(".animation-target .attrName");
   const regexp = new RegExp(`\\${ selector }(\\.|$)`, "gi");
 
   for (const attrNameEl of attrNameEls) {
     if (regexp.exec(attrNameEl.textContent)) {
       return attrNameEl.closest(".animation-item");
--- a/devtools/client/inspector/animation/utils/l10n.js
+++ b/devtools/client/inspector/animation/utils/l10n.js
@@ -2,16 +2,18 @@
  * 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 { LocalizationHelper } = require("devtools/shared/l10n");
 const L10N =
   new LocalizationHelper("devtools/client/locales/animationinspector.properties");
+const INSPECTOR_L10N =
+  new LocalizationHelper("devtools/client/locales/inspector.properties");
 
 /**
  * Get a formatted title for this animation. This will be either:
  * "%S", "%S : CSS Transition", "%S : CSS Animation",
  * "%S : Script Animation", or "Script Animation", depending
  * if the server provides the type, what type it is and if the animation
  * has a name.
  *
@@ -31,11 +33,12 @@ function getFormattedTitle(state) {
   }
 
   return L10N.getFormatStr(`timeline.${state.type}.nameLabel`, state.name);
 }
 
 module.exports = {
   getFormatStr: (...args) => L10N.getFormatStr(...args),
   getFormattedTitle,
+  getInspectorStr: (...args) => INSPECTOR_L10N.getStr(...args),
   getStr: (...args) => L10N.getStr(...args),
   numberWithDecimals: (...args) => L10N.numberWithDecimals(...args),
 };
--- a/devtools/client/inspector/boxmodel/components/BoxModelMain.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelMain.js
@@ -484,59 +484,59 @@ class BoxModelMain extends PureComponent
       dom.div(
         {
           className: "boxmodel-box"
         },
         dom.span(
           {
             className: "boxmodel-legend",
             "data-box": "margin",
-            title: BOXMODEL_L10N.getStr("boxmodel.margin"),
+            title: "margin",
           },
-          BOXMODEL_L10N.getStr("boxmodel.margin")
+          "margin"
         ),
         dom.div(
           {
             className: "boxmodel-margins",
             "data-box": "margin",
-            title: BOXMODEL_L10N.getStr("boxmodel.margin"),
+            title: "margin",
             ref: div => {
               this.marginLayout = div;
             },
           },
           dom.span(
             {
               className: "boxmodel-legend",
               "data-box": "border",
-              title: BOXMODEL_L10N.getStr("boxmodel.border"),
+              title: "border",
             },
-            BOXMODEL_L10N.getStr("boxmodel.border")
+            "border"
           ),
           dom.div(
             {
               className: "boxmodel-borders",
               "data-box": "border",
-              title: BOXMODEL_L10N.getStr("boxmodel.border"),
+              title: "border",
               ref: div => {
                 this.borderLayout = div;
               },
             },
             dom.span(
               {
                 className: "boxmodel-legend",
                 "data-box": "padding",
-                title: BOXMODEL_L10N.getStr("boxmodel.padding"),
+                title: "padding",
               },
-              BOXMODEL_L10N.getStr("boxmodel.padding")
+              "padding"
             ),
             dom.div(
               {
                 className: "boxmodel-paddings",
                 "data-box": "padding",
-                title: BOXMODEL_L10N.getStr("boxmodel.padding"),
+                title: "padding",
                 ref: div => {
                   this.paddingLayout = div;
                 },
               },
               dom.div({
                 className: "boxmodel-contents",
                 "data-box": "content",
                 title: BOXMODEL_L10N.getStr("boxmodel.content"),
--- a/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_03.js
+++ b/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_03.js
@@ -36,17 +36,17 @@ const TEST_DATA = [
   [":", "style=\"color:aliceblue\"", 13, 22, true],
   ["b", "style=\"color:beige\"", 14, 18, true],
   ["VK_RIGHT", "style=\"color:beige\"", 18, 18, false],
   [";", "style=\"color:beige;\"", 19, 19, false],
   [";", "style=\"color:beige;;\"", 20, 20, false],
   ["VK_LEFT", "style=\"color:beige;;\"", 19, 19, false],
   ["p", "style=\"color:beige;padding;\"", 20, 26, true],
   ["VK_RIGHT", "style=\"color:beige;padding;\"", 26, 26, false],
-  [":", "style=\"color:beige;padding:calc;\"", 27, 31, true],
+  [":", "style=\"color:beige;padding:inherit;\"", 27, 34, true],
   ["0", "style=\"color:beige;padding:0;\"", 28, 28, false],
   ["VK_RETURN", "style=\"color:beige;padding:0;\"",
    -1, -1, false]
 ];
 
 add_task(async function() {
   let {inspector} = await openInspectorForURL(TEST_URL);
 
--- a/devtools/client/inspector/shared/highlighters-overlay.js
+++ b/devtools/client/inspector/shared/highlighters-overlay.js
@@ -384,16 +384,50 @@ class HighlightersOverlay {
       this.state.grid.options);
     this.gridHighlighterShown = null;
 
     // Erase grid highlighter state.
     this.state.grid = {};
   }
 
   /**
+   * Show the box model highlighter for the given node.
+   *
+   * @param  {NodeFront} node
+   *         The NodeFront of the element to highlight.
+   * @param  {Object} options
+   *         Object used for passing options to the box model highlighter.
+   */
+  async showBoxModelHighlighter(node, options) {
+    const highlighter = await this._getHighlighter("BoxModelHighlighter");
+    if (!highlighter) {
+      return;
+    }
+
+    const isShown = await highlighter.show(node, options);
+    if (!isShown) {
+      return;
+    }
+
+    this.boxModelHighlighterShown = node;
+  }
+
+  /**
+   * Hide the box model highlighter.
+   */
+  async hideBoxModelHighlighter() {
+    if (!this.boxModelHighlighterShown || !this.highlighters.BoxModelHighlighter) {
+      return;
+    }
+
+    await this.highlighters.BoxModelHighlighter.hide();
+    this.boxModelHighlighterShown = null;
+  }
+
+  /**
    * Toggle the geometry editor highlighter for the given element.
    *
    * @param {NodeFront} node
    *        The NodeFront of the element to highlight.
    */
   async toggleGeometryHighlighter(node) {
     if (node == this.geometryEditorHighlighterShown) {
       await this.hideGeometryEditor();
@@ -866,16 +900,17 @@ class HighlightersOverlay {
     this._hideHighlighterIfDeadNode(this.shapesHighlighterShown,
       this.hideShapesHighlighter);
   }
 
   /**
    * Clear saved highlighter shown properties on will-navigate.
    */
   onWillNavigate() {
+    this.boxModelHighlighterShown = null;
     this.flexboxHighlighterShown = null;
     this.geometryEditorHighlighterShown = null;
     this.gridHighlighterShown = null;
     this.hoveredHighlighterShown = null;
     this.selectorHighlighterShown = null;
     this.shapesHighlighterShown = null;
     this.destroyEditors();
   }
@@ -921,16 +956,17 @@ class HighlightersOverlay {
 
     this._lastHovered = null;
 
     this.inspector = null;
     this.highlighterUtils = null;
     this.supportsHighlighters = null;
     this.state = null;
 
+    this.boxModelHighlighterShown = null;
     this.flexboxHighlighterShown = null;
     this.geometryEditorHighlighterShown = null;
     this.gridHighlighterShown = null;
     this.hoveredHighlighterShown = null;
     this.selectorHighlighterShown = null;
     this.shapesHighlighterShown = null;
 
     this.destroyed = true;
--- a/devtools/client/locales/en-US/boxmodel.properties
+++ b/devtools/client/locales/en-US/boxmodel.properties
@@ -14,28 +14,16 @@
 # LOCALIZATION NOTE (boxmodel.title) This is the title of the box model panel and is
 # displayed as a label.
 boxmodel.title=Box Model
 
 # LOCALIZATION NOTE (boxmodel.position) This refers to the position in the box model and
 # might be displayed as a label or as a tooltip.
 boxmodel.position=position
 
-# LOCALIZATION NOTE (boxmodel.margin) This refers to the margin in the box model and
-# might be displayed as a label or as a tooltip.
-boxmodel.margin=margin
-
-# LOCALIZATION NOTE (boxmodel.border) This refers to the border in the box model and
-# might be displayed as a label or as a tooltip.
-boxmodel.border=border
-
-# LOCALIZATION NOTE (boxmodel.padding) This refers to the padding in the box model and
-# might be displayed as a label or as a tooltip.
-boxmodel.padding=padding
-
 # LOCALIZATION NOTE (boxmodel.content) This refers to the content in the box model and
 # might be displayed as a label or as a tooltip.
 boxmodel.content=content
 
 # LOCALIZATION NOTE: (boxmodel.geometryButton.tooltip) This label is displayed as a
 # tooltip that appears when hovering over the button that allows users to edit the
 # position of an element in the page.
 boxmodel.geometryButton.tooltip=Edit position
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -237,16 +237,19 @@ pref("devtools.scratchpad.enabled", fals
 pref("devtools.dom.enabled", false);
 
 // Make sure the Accessibility panel is hidden by default
 pref("devtools.accessibility.enabled", false);
 
 // Web Audio Editor Inspector Width should be a preference
 pref("devtools.webaudioeditor.inspectorWidth", 300);
 
+// Experimental UI for the browser console that doesn't use a XUL wrapper doc
+pref("devtools.browserconsole.html", false);
+
 // Web console filters
 pref("devtools.webconsole.filter.error", true);
 pref("devtools.webconsole.filter.warn", true);
 pref("devtools.webconsole.filter.info", true);
 pref("devtools.webconsole.filter.log", true);
 pref("devtools.webconsole.filter.debug", true);
 pref("devtools.webconsole.filter.css", false);
 pref("devtools.webconsole.filter.net", false);
--- a/devtools/client/responsive.html/browser/content.js
+++ b/devtools/client/responsive.html/browser/content.js
@@ -178,21 +178,15 @@ var global = this;
 
   let WebProgressListener = {
     onLocationChange(webProgress, request, URI, flags) {
       if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
         return;
       }
       makeScrollbarsFloating();
     },
-    QueryInterface: function QueryInterface(iid) {
-      if (iid.equals(Ci.nsIWebProgressListener) ||
-          iid.equals(Ci.nsISupportsWeakReference) ||
-          iid.equals(Ci.nsISupports)) {
-        return this;
-      }
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener",
+                                            "nsISupportsWeakReference"]),
   };
 })();
 
 global.responsiveFrameScriptLoaded = true;
 sendAsyncMessage("ResponsiveMode:ChildScriptReady");
--- a/devtools/client/responsive.html/browser/web-navigation.js
+++ b/devtools/client/responsive.html/browser/web-navigation.js
@@ -29,18 +29,17 @@ function readInputStreamToString(stream)
  */
 function BrowserElementWebNavigation(browser) {
   this._browser = browser;
 }
 
 BrowserElementWebNavigation.prototype = {
 
   QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsIWebNavigation,
-    Ci.nsISupports
+    Ci.nsIWebNavigation
   ]),
 
   get _mm() {
     return this._browser.frameLoader.messageManager;
   },
 
   canGoBack: false,
   canGoForward: false,
--- a/devtools/client/shared/test/unit/test_cssColorDatabase.js
+++ b/devtools/client/shared/test/unit/test_cssColorDatabase.js
@@ -42,17 +42,21 @@ function checkOne(colorName, checkName) 
 function run_test() {
   for (let name in cssColors) {
     checkOne(name, true);
   }
   checkOne("transparent", false);
 
   // Now check that platform didn't add a new name when we weren't
   // looking.
-  let names = InspectorUtils.getCSSValuesForProperty("background-color");
-  for (let name of names) {
-    if (name !== "hsl" && name !== "hsla" &&
-        name !== "rgb" && name !== "rgba" &&
-        name !== "inherit" && name !== "initial" && name !== "unset") {
-      checkOne(name, true);
+  // XXX Disable this test for now as getCSSValuesForProperty no longer
+  //     returns the complete color keyword list.
+  if (false) {
+    let names = InspectorUtils.getCSSValuesForProperty("background-color");
+    for (let name of names) {
+      if (name !== "hsl" && name !== "hsla" &&
+          name !== "rgb" && name !== "rgba" &&
+          name !== "inherit" && name !== "initial" && name !== "unset") {
+        checkOne(name, true);
+      }
     }
   }
 }
--- a/devtools/client/sourceeditor/test/css_autocompletion_tests.json
+++ b/devtools/client/sourceeditor/test/css_autocompletion_tests.json
@@ -20,17 +20,17 @@
                "-moz-appearance"]],
     [[12, 20], ["none", "number-input"]],
     [[12, 22], ["none"]],
     [[17, 22], ["hsl", "hsla"]],
     [[19, 10], ["background", "background-attachment", "background-blend-mode",
                 "background-clip", "background-color", "background-image",
                 "background-origin", "background-position", "background-position-x",
                 "background-position-y", "background-repeat", "background-size"]],
-    [[21,  9], ["auto", "calc", "inherit", "initial","unset"]],
+    [[21,  9], ["auto", "inherit", "initial","unset"]],
     [[25, 26], [".devtools-toolbarbutton > tab",
                 ".devtools-toolbarbutton > hbox",
                 ".devtools-toolbarbutton > .toolbarbutton-menubutton-button"]],
     [[25, 31], [".devtools-toolbarbutton > hbox.toolbarbutton-menubutton-button"]],
     [[29, 20], [".devtools-menulist:after", ".devtools-menulist:active"]],
     [[30, 10], ["#devtools-anotherone", "#devtools-itjustgoeson", "#devtools-menu",
                 "#devtools-okstopitnow", "#devtools-toolbarbutton", "#devtools-yetagain"]],
     [[39, 39], [".devtools-toolbarbutton:not([label]) > tab"]],
--- a/devtools/client/themes/animation.css
+++ b/devtools/client/themes/animation.css
@@ -231,26 +231,34 @@ select.playback-rate-selector.devtools-b
   height: 100%;
   padding-left: 4px;
   width: var(--sidebar-width);
 }
 
 /* Reps component */
 .animation-target .objectBox {
   display: flex;
-  width: 100%;
+  max-width: 100%;
 }
 
 .animation-target .objectBox .attrName {
   min-width: 0;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
 
+.animation-target .objectBox:hover .open-inspector {
+  background-color: var(--comment-node-color);
+}
+
+.animation-target.highlighting .objectBox .open-inspector {
+  background-color: var(--theme-highlight-blue);
+}
+
 /* Summary Graph */
 .animation-summary-graph {
   cursor: pointer;
   height: 100%;
   padding-top: 5px;
   position: relative;
   width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
 }
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -178,31 +178,37 @@ HUD_SERVICE.prototype =
 
       let client = new DebuggerClient(DebuggerServer.connectPipe());
       await client.connect();
       let response = await client.getProcess();
       return { form: response.form, client, chrome: true, isTabActor: true };
     }
 
     async function openWindow(t) {
-      let browserConsoleURL = Tools.webConsole.browserConsoleURL;
-      let win = Services.ww.openWindow(null, browserConsoleURL, "_blank",
-                                       BC_WINDOW_FEATURES, null);
+      let win = Services.ww.openWindow(null, Tools.webConsole.browserConsoleURL,
+                                       "_blank", BC_WINDOW_FEATURES, null);
+      let iframeWindow = win;
+
       await new Promise(resolve => {
         win.addEventListener("DOMContentLoaded", resolve, {once: true});
       });
 
       win.document.title = l10n.getStr("browserConsole.title");
 
-      let iframe = win.document.querySelector("iframe");
-      await new Promise(resolve => {
-        iframe.addEventListener("DOMContentLoaded", resolve, {once: true});
-      });
+      // With a XUL wrapper doc, we host webconsole.html in an iframe.
+      // Wait for that to be ready before resolving:
+      if (!Tools.webConsole.browserConsoleUsesHTML) {
+        let iframe = win.document.querySelector("iframe");
+        await new Promise(resolve => {
+          iframe.addEventListener("DOMContentLoaded", resolve, {once: true});
+        });
+        iframeWindow = iframe.contentWindow;
+      }
 
-      return {iframeWindow: iframe.contentWindow, chromeWindow: win};
+      return {iframeWindow, chromeWindow: win};
     }
 
     // Temporarily cache the async startup sequence so that if toggleBrowserConsole
     // gets called again we can return this console instead of opening another one.
     this._browserConsoleInitializing = (async () => {
       let connection = await connect();
       let target = await TargetFactory.forRemoteTab(connection);
       let {iframeWindow, chromeWindow} = await openWindow(target);
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -327,16 +327,17 @@ subsuite = clipboard
 [browser_webconsole_repeat_different_objects.js]
 [browser_webconsole_sandbox_update_after_navigation.js]
 [browser_webconsole_script_errordoc_urls.js]
 [browser_webconsole_scroll.js]
 [browser_webconsole_select_all.js]
 [browser_webconsole_show_subresource_security_errors.js]
 [browser_webconsole_shows_reqs_from_netmonitor.js]
 [browser_webconsole_shows_reqs_in_netmonitor.js]
+[browser_webconsole_sidebar_object_expand_when_message_pruned.js]
 [browser_webconsole_sourcemap_css.js]
 [browser_webconsole_sourcemap_error.js]
 [browser_webconsole_sourcemap_invalid.js]
 [browser_webconsole_sourcemap_nosource.js]
 [browser_webconsole_split.js]
 [browser_webconsole_split_escape_key.js]
 [browser_webconsole_split_focus.js]
 [browser_webconsole_split_persist.js]
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_network_requests_from_chrome.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_network_requests_from_chrome.js
@@ -9,17 +9,17 @@
 "use strict";
 
 const TEST_URI = "http://example.com/";
 
 add_task(async function() {
   // Start a listener on the console service.
   let good = true;
   const listener = {
-    QueryInterface: XPCOMUtils.generateQI([ Ci.nsIObserver ]),
+    QueryInterface: ChromeUtils.generateQI([ Ci.nsIObserver ]),
     observe: function(subject) {
       if (subject instanceof Ci.nsIScriptError &&
           subject.category === "XPConnect JavaScript" &&
           subject.sourceName.includes("webconsole")) {
         good = false;
       }
     }
   };
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_observer_notifications.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_observer_notifications.js
@@ -16,20 +16,18 @@ add_task(async function() {
   await openNewTabAndConsole(TEST_URI);
   await waitFor(() => created);
 
   await closeTabAndToolbox(gBrowser.selectedTab);
   await waitFor(() => destroyed);
 });
 
 function setupObserver() {
-  const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {});
-
   const observer = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
     observe: function observe(subject, topic) {
       subject = subject.QueryInterface(Ci.nsISupportsString);
 
       switch (topic) {
         case "web-console-created":
           ok(HUDService.getHudReferenceById(subject.data), "We have a hud reference");
           Services.obs.removeObserver(observer, "web-console-created");
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_sidebar_object_expand_when_message_pruned.js
@@ -0,0 +1,80 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test that an object in the sidebar can still be expanded after the message where it was
+// logged is pruned.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf8," +
+  "<script>console.log({a:1,b:2,c:[3,4,5]});</script>";
+
+add_task(async function() {
+  // Should be removed when sidebar work is complete (Bug 1447235)
+  await pushPref("devtools.webconsole.sidebarToggle", true);
+  // Set the loglimit to 1 so message gets pruned as soon as another message is displayed.
+  await pushPref("devtools.hud.loglimit", 1);
+
+  let hud = await openNewTabAndConsole(TEST_URI);
+
+  let message = await waitFor(() => findMessage(hud, "Object"));
+  let object = message.querySelector(".object-inspector .objectBox-object");
+
+  const sidebar = await showSidebarWithContextMenu(hud, object, true);
+
+  let oi = sidebar.querySelector(".object-inspector");
+  let oiNodes = oi.querySelectorAll(".node");
+  if (oiNodes.length === 1) {
+    // If this is the case, we wait for the properties to be fetched and displayed.
+    await waitFor(() => oi.querySelectorAll(".node").length > 1);
+    oiNodes = oi.querySelectorAll(".node");
+  }
+
+  info("Log a message so the original one gets pruned");
+  const messageText = "hello world";
+  const onMessage = waitForMessage(hud, messageText);
+  ContentTask.spawn(gBrowser.selectedBrowser, messageText, async function(str) {
+    content.console.log(str);
+  });
+  await onMessage;
+
+  ok(!findMessage(hud, "Object"), "Message with object was pruned");
+
+  info("Expand the 'c' node in the sidebar");
+  // Here's what the object in the sidebar looks like:
+  // ▼ {…}
+  //     a: 1
+  //     b: 2
+  //   ▶︎ c: (3) […]
+  //   ▶︎ <prototype>: {…}
+  const cNode = oiNodes[3];
+  const onNodeExpanded = waitFor(() => oi.querySelectorAll(".node").length > 5);
+  cNode.click();
+  await onNodeExpanded;
+
+  // Here's what the object in the sidebar should look like:
+  // ▼ {…}
+  //     a: 1
+  //     b: 2
+  //   ▼ c: (3) […]
+  //       0: 3
+  //       1: 4
+  //       2: 5
+  //       length: 3
+  //     ▶︎ <prototype>: []
+  //   ▶︎ <prototype>: {…}
+  is(oi.querySelectorAll(".node").length, 10, "The 'c' property was expanded");
+});
+
+async function showSidebarWithContextMenu(hud, node) {
+  let wrapper = hud.ui.document.querySelector(".webconsole-output-wrapper");
+  let onSidebarShown = waitFor(() => wrapper.querySelector(".sidebar"));
+
+  let contextMenu = await openContextMenu(hud, node);
+  let openInSidebar = contextMenu.querySelector("#console-menu-open-sidebar");
+  openInSidebar.click();
+  await onSidebarShown;
+  await hideContextMenu(hud);
+  return onSidebarShown;
+}
--- a/devtools/server/actors/highlighters.js
+++ b/devtools/server/actors/highlighters.js
@@ -576,18 +576,17 @@ HighlighterEnvironment.prototype = {
     this._win = win;
 
     // We need a progress listener to know when the window will navigate/has
     // navigated.
     let self = this;
     this.listener = {
       QueryInterface: XPCOMUtils.generateQI([
         Ci.nsIWebProgressListener,
-        Ci.nsISupportsWeakReference,
-        Ci.nsISupports
+        Ci.nsISupportsWeakReference
       ]),
 
       onStateChange: function(progress, request, flag) {
         let isStart = flag & Ci.nsIWebProgressListener.STATE_START;
         let isStop = flag & Ci.nsIWebProgressListener.STATE_STOP;
         let isWindow = flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
         let isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
 
--- a/devtools/server/actors/inspector/node.js
+++ b/devtools/server/actors/inspector/node.js
@@ -403,17 +403,17 @@ const NodeActor = protocol.ActorClassWit
     let line = 0;
     let native = false;
     let override = listener.override || {};
     let tags = listener.tags || "";
     let type = listener.type || "";
     let url = "";
 
     // If the listener is an object with a 'handleEvent' method, use that.
-    if (listenerDO.class === "Object" || listenerDO.class === "XULElement") {
+    if (listenerDO.class === "Object" || /^XUL\w*Element$/.test(listenerDO.class)) {
       let desc;
 
       while (!desc && listenerDO) {
         desc = listenerDO.getOwnPropertyDescriptor("handleEvent");
         listenerDO = listenerDO.proto;
       }
 
       if (desc && desc.value) {
--- a/devtools/server/actors/tab.js
+++ b/devtools/server/actors/tab.js
@@ -1503,17 +1503,16 @@ function DebuggerProgressListener(tabAct
 
   this._watchedDocShells = new WeakSet();
 }
 
 DebuggerProgressListener.prototype = {
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIWebProgressListener,
     Ci.nsISupportsWeakReference,
-    Ci.nsISupports,
   ]),
 
   destroy() {
     Services.obs.removeObserver(this, "inner-window-destroyed");
     this._knownWindowIDs.clear();
     this._knownWindowIDs = null;
   },
 
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -1141,17 +1141,17 @@ const ThreadActor = ActorClassWithSpec(t
           listenerForm.isEventHandler = !!node.hasAttribute(handlerName);
         }
         if (node[handlerName]) {
           listenerForm.isEventHandler = !!node[handlerName];
         }
         // Get the Debugger.Object for the listener object.
         let listenerDO = this.globalDebugObject.makeDebuggeeValue(listener);
         // If the listener is an object with a 'handleEvent' method, use that.
-        if (listenerDO.class == "Object" || listenerDO.class == "XULElement") {
+        if (listenerDO.class === "Object" || /^XUL\w*Element$/.test(listenerDO.class)) {
           // For some events we don't have permission to access the
           // 'handleEvent' property when running in content scope.
           if (!listenerDO.unwrap()) {
             continue;
           }
           let heDesc;
           while (!heDesc && listenerDO) {
             heDesc = listenerDO.getOwnPropertyDescriptor("handleEvent");
--- a/devtools/server/actors/webextension-inspected-window.js
+++ b/devtools/server/actors/webextension-inspected-window.js
@@ -108,18 +108,17 @@ function CustomizedReload(params) {
   this.injectedScript = params.injectedScript;
   this.userAgent = params.userAgent;
 
   this.customizedReloadWindows = new WeakSet();
 }
 
 CustomizedReload.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsISupports]),
+                                         Ci.nsISupportsWeakReference]),
   get window() {
     return this.docShell.DOMWindow;
   },
 
   get webNavigation() {
     return this.docShell
                .QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIWebNavigation);
--- a/devtools/server/tests/mochitest/test_css-properties.html
+++ b/devtools/server/tests/mochitest/test_css-properties.html
@@ -79,17 +79,17 @@ window.onload = function() {
     ok(cssProperties.isKnown("--foob\\{ar"),
       "A CSS variable with escaped character properly evaluates.");
     ok(cssProperties.isKnown("--fübar"),
       "A CSS variable unicode properly evaluates.");
     ok(!cssProperties.isKnown("--foo bar"),
       "A CSS variable with spaces fails");
 
     is(toSortedString(cssProperties.getValues("margin")),
-       toSortedString(["auto", "calc", "inherit", "initial", "unset"]),
+       toSortedString(["auto", "inherit", "initial", "unset"]),
        "Can get values for the CSS margin.");
     is(cssProperties.getValues("foobar").length, 0,
       "Unknown values return an empty array.");
 
     const bgColorValues = cssProperties.getValues("background-color");
     ok(bgColorValues.includes("blanchedalmond"),
       "A property with color values includes blanchedalmond.");
     ok(bgColorValues.includes("papayawhip"),
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -36,16 +36,17 @@ exports.CSS_PROPERTIES = {
       "backwards",
       "both",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
       "forwards",
+      "frames",
       "infinite",
       "inherit",
       "initial",
       "linear",
       "none",
       "normal",
       "paused",
       "reverse",
@@ -161,16 +162,17 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
+      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -348,17 +350,16 @@ exports.CSS_PROPERTIES = {
       "border-inline-end-style",
       "border-inline-end-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -423,17 +424,16 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-border-end-width": {
     "isInherited": false,
     "subproperties": [
       "border-inline-end-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -451,16 +451,22 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
+      "auto",
       "fill",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
       "repeat",
       "repeating-linear-gradient",
@@ -479,17 +485,16 @@ exports.CSS_PROPERTIES = {
       "border-inline-start-style",
       "border-inline-start-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -554,17 +559,16 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-border-start-width": {
     "isInherited": false,
     "subproperties": [
       "border-inline-start-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -698,17 +702,16 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-column-gap": {
     "isInherited": false,
     "subproperties": [
       "column-gap"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "-moz-column-rule": {
     "isInherited": false,
@@ -717,17 +720,16 @@ exports.CSS_PROPERTIES = {
       "column-rule-style",
       "column-rule-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -792,63 +794,61 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-column-rule-width": {
     "isInherited": false,
     "subproperties": [
       "column-rule-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
   "-moz-column-width": {
     "isInherited": false,
     "subproperties": [
       "column-width"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-moz-columns": {
     "isInherited": false,
     "subproperties": [
       "column-count",
       "column-width"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-moz-context-properties": {
     "isInherited": true,
     "subproperties": [
       "-moz-context-properties"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
+      "none",
       "unset"
     ]
   },
   "-moz-control-character-visibility": {
     "isInherited": true,
     "subproperties": [
       "-moz-control-character-visibility"
     ],
@@ -879,16 +879,17 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "font-feature-settings"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
+      "normal",
       "unset"
     ]
   },
   "-moz-font-language-override": {
     "isInherited": true,
     "subproperties": [
       "font-language-override"
     ],
@@ -929,44 +930,44 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-image-region": {
     "isInherited": true,
     "subproperties": [
       "-moz-image-region"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "auto",
+      "inherit",
+      "initial",
+      "rect",
       "unset"
     ]
   },
   "-moz-margin-end": {
     "isInherited": false,
     "subproperties": [
       "margin-inline-end"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-moz-margin-start": {
     "isInherited": false,
     "subproperties": [
       "margin-inline-start"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-moz-orient": {
     "isInherited": false,
     "subproperties": [
@@ -1048,30 +1049,28 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-padding-end": {
     "isInherited": false,
     "subproperties": [
       "padding-inline-end"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-moz-padding-start": {
     "isInherited": false,
     "subproperties": [
       "padding-inline-start"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-moz-perspective": {
     "isInherited": false,
     "subproperties": [
@@ -1088,17 +1087,16 @@ exports.CSS_PROPERTIES = {
   "-moz-perspective-origin": {
     "isInherited": false,
     "subproperties": [
       "perspective-origin"
     ],
     "supports": [],
     "values": [
       "bottom",
-      "calc",
       "center",
       "inherit",
       "initial",
       "left",
       "right",
       "top",
       "unset"
     ]
@@ -1121,17 +1119,16 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-tab-size": {
     "isInherited": true,
     "subproperties": [
       "-moz-tab-size"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-moz-text-size-adjust": {
     "isInherited": true,
     "subproperties": [
@@ -1148,18 +1145,42 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-transform": {
     "isInherited": false,
     "subproperties": [
       "transform"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "accumulatematrix",
+      "inherit",
+      "initial",
+      "interpolatematrix",
+      "matrix",
+      "matrix3d",
+      "none",
+      "perspective",
+      "rotate",
+      "rotate3d",
+      "rotateX",
+      "rotateY",
+      "rotateZ",
+      "scale",
+      "scale3d",
+      "scaleX",
+      "scaleY",
+      "scaleZ",
+      "skew",
+      "skewX",
+      "skewY",
+      "translate",
+      "translate3d",
+      "translateX",
+      "translateY",
+      "translateZ",
       "unset"
     ]
   },
   "-moz-transform-origin": {
     "isInherited": false,
     "subproperties": [
       "transform-origin"
     ],
@@ -1202,16 +1223,17 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "all",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
+      "frames",
       "inherit",
       "initial",
       "linear",
       "none",
       "step-end",
       "step-start",
       "steps",
       "unset"
@@ -1264,16 +1286,17 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
+      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -1379,18 +1402,42 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-window-transform": {
     "isInherited": false,
     "subproperties": [
       "-moz-window-transform"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "accumulatematrix",
+      "inherit",
+      "initial",
+      "interpolatematrix",
+      "matrix",
+      "matrix3d",
+      "none",
+      "perspective",
+      "rotate",
+      "rotate3d",
+      "rotateX",
+      "rotateY",
+      "rotateZ",
+      "scale",
+      "scale3d",
+      "scaleX",
+      "scaleY",
+      "scaleZ",
+      "skew",
+      "skewX",
+      "skewY",
+      "translate",
+      "translate3d",
+      "translateX",
+      "translateY",
+      "translateZ",
       "unset"
     ]
   },
   "-moz-window-transform-origin": {
     "isInherited": false,
     "subproperties": [
       "-moz-window-transform-origin"
     ],
@@ -1411,80 +1458,83 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "align-content"
     ],
     "supports": [],
     "values": [
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
-      "left",
       "normal",
-      "right",
+      "safe",
       "space-around",
       "space-between",
       "space-evenly",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "-webkit-align-items": {
     "isInherited": false,
     "subproperties": [
       "align-items"
     ],
     "supports": [],
     "values": [
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
-      "left",
       "normal",
-      "right",
+      "safe",
       "self-end",
       "self-start",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "-webkit-align-self": {
     "isInherited": false,
     "subproperties": [
       "align-self"
     ],
     "supports": [],
     "values": [
       "auto",
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
-      "left",
       "normal",
-      "right",
+      "safe",
       "self-end",
       "self-start",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "-webkit-animation": {
     "isInherited": false,
     "subproperties": [
       "animation-duration",
       "animation-timing-function",
@@ -1504,16 +1554,17 @@ exports.CSS_PROPERTIES = {
       "backwards",
       "both",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
       "forwards",
+      "frames",
       "infinite",
       "inherit",
       "initial",
       "linear",
       "none",
       "normal",
       "paused",
       "reverse",
@@ -1629,16 +1680,17 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
+      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -1690,16 +1742,17 @@ exports.CSS_PROPERTIES = {
   },
   "-webkit-background-size": {
     "isInherited": false,
     "subproperties": [
       "background-size"
     ],
     "supports": [],
     "values": [
+      "auto",
       "contain",
       "cover",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-webkit-border-bottom-left-radius": {
@@ -1740,16 +1793,22 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
+      "auto",
       "fill",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
       "repeat",
       "repeating-linear-gradient",
@@ -1892,17 +1951,16 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "box-shadow"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "hsl",
       "hsla",
       "inherit",
       "initial",
       "inset",
       "none",
       "rgb",
@@ -1927,36 +1985,47 @@ exports.CSS_PROPERTIES = {
   },
   "-webkit-filter": {
     "isInherited": false,
     "subproperties": [
       "filter"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
-      "unset"
+      "blur",
+      "brightness",
+      "contrast",
+      "drop-shadow",
+      "grayscale",
+      "hue-rotate",
+      "inherit",
+      "initial",
+      "invert",
+      "none",
+      "opacity",
+      "saturate",
+      "sepia",
+      "unset",
+      "url"
     ]
   },
   "-webkit-flex": {
     "isInherited": false,
     "subproperties": [
       "flex-grow",
       "flex-shrink",
       "flex-basis"
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "content",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-webkit-flex-basis": {
     "isInherited": false,
@@ -1965,17 +2034,16 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "content",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-webkit-flex-direction": {
     "isInherited": false,
@@ -2054,32 +2122,32 @@ exports.CSS_PROPERTIES = {
   },
   "-webkit-justify-content": {
     "isInherited": false,
     "subproperties": [
       "justify-content"
     ],
     "supports": [],
     "values": [
-      "baseline",
       "center",
       "end",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
-      "last baseline",
       "left",
       "normal",
       "right",
+      "safe",
       "space-around",
       "space-between",
       "space-evenly",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "-webkit-mask": {
     "isInherited": false,
     "subproperties": [
       "mask-image",
       "mask-repeat",
@@ -2096,18 +2164,24 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
       "add",
       "alpha",
+      "auto",
       "border-box",
       "bottom",
       "center",
       "contain",
       "content-box",
       "cover",
       "exclude",
       "fill-box",
@@ -2184,16 +2258,21 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
       "unset",
@@ -2238,39 +2317,35 @@ exports.CSS_PROPERTIES = {
   },
   "-webkit-mask-position-x": {
     "isInherited": false,
     "subproperties": [
       "mask-position-x"
     ],
     "supports": [],
     "values": [
-      "bottom",
       "center",
       "inherit",
       "initial",
       "left",
       "right",
-      "top",
       "unset"
     ]
   },
   "-webkit-mask-position-y": {
     "isInherited": false,
     "subproperties": [
       "mask-position-y"
     ],
     "supports": [],
     "values": [
       "bottom",
       "center",
       "inherit",
       "initial",
-      "left",
-      "right",
       "top",
       "unset"
     ]
   },
   "-webkit-mask-repeat": {
     "isInherited": false,
     "subproperties": [
       "mask-repeat"
@@ -2290,16 +2365,17 @@ exports.CSS_PROPERTIES = {
   },
   "-webkit-mask-size": {
     "isInherited": false,
     "subproperties": [
       "mask-size"
     ],
     "supports": [],
     "values": [
+      "auto",
       "contain",
       "cover",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "-webkit-order": {
@@ -2330,17 +2406,16 @@ exports.CSS_PROPERTIES = {
   "-webkit-perspective-origin": {
     "isInherited": false,
     "subproperties": [
       "perspective-origin"
     ],
     "supports": [],
     "values": [
       "bottom",
-      "calc",
       "center",
       "inherit",
       "initial",
       "left",
       "right",
       "top",
       "unset"
     ]
@@ -2386,17 +2461,16 @@ exports.CSS_PROPERTIES = {
       "-webkit-text-stroke-width",
       "-webkit-text-stroke-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "hsl",
       "hsla",
       "inherit",
       "initial",
       "medium",
       "rgb",
       "rgba",
@@ -2429,34 +2503,57 @@ exports.CSS_PROPERTIES = {
   },
   "-webkit-text-stroke-width": {
     "isInherited": true,
     "subproperties": [
       "-webkit-text-stroke-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
   "-webkit-transform": {
     "isInherited": false,
     "subproperties": [
       "transform"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "accumulatematrix",
+      "inherit",
+      "initial",
+      "interpolatematrix",
+      "matrix",
+      "matrix3d",
+      "none",
+      "perspective",
+      "rotate",
+      "rotate3d",
+      "rotateX",
+      "rotateY",
+      "rotateZ",
+      "scale",
+      "scale3d",
+      "scaleX",
+      "scaleY",
+      "scaleZ",
+      "skew",
+      "skewX",
+      "skewY",
+      "translate",
+      "translate3d",
+      "translateX",
+      "translateY",
+      "translateZ",
       "unset"
     ]
   },
   "-webkit-transform-origin": {
     "isInherited": false,
     "subproperties": [
       "transform-origin"
     ],
@@ -2499,16 +2596,17 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "all",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
+      "frames",
       "inherit",
       "initial",
       "linear",
       "none",
       "step-end",
       "step-start",
       "steps",
       "unset"
@@ -2561,16 +2659,17 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
+      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -2603,80 +2702,83 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "align-content"
     ],
     "supports": [],
     "values": [
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
-      "left",
       "normal",
-      "right",
+      "safe",
       "space-around",
       "space-between",
       "space-evenly",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "align-items": {
     "isInherited": false,
     "subproperties": [
       "align-items"
     ],
     "supports": [],
     "values": [
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
-      "left",
       "normal",
-      "right",
+      "safe",
       "self-end",
       "self-start",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "align-self": {
     "isInherited": false,
     "subproperties": [
       "align-self"
     ],
     "supports": [],
     "values": [
       "auto",
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
-      "left",
       "normal",
-      "right",
+      "safe",
       "self-end",
       "self-start",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "all": {
     "isInherited": false,
     "subproperties": [
       "align-content",
       "align-items",
@@ -3023,16 +3125,17 @@ exports.CSS_PROPERTIES = {
       "backwards",
       "both",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
       "forwards",
+      "frames",
       "infinite",
       "inherit",
       "initial",
       "linear",
       "none",
       "normal",
       "paused",
       "reverse",
@@ -3148,16 +3251,17 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
+      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -3196,16 +3300,22 @@ exports.CSS_PROPERTIES = {
     "values": [
       "COLOR",
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
+      "auto",
       "border-box",
       "bottom",
       "center",
       "contain",
       "content-box",
       "cover",
       "currentColor",
       "fixed",
@@ -3328,16 +3438,21 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
       "unset",
@@ -3379,39 +3494,35 @@ exports.CSS_PROPERTIES = {
   },
   "background-position-x": {
     "isInherited": false,
     "subproperties": [
       "background-position-x"
     ],
     "supports": [],
     "values": [
-      "bottom",
       "center",
       "inherit",
       "initial",
       "left",
       "right",
-      "top",
       "unset"
     ]
   },
   "background-position-y": {
     "isInherited": false,
     "subproperties": [
       "background-position-y"
     ],
     "supports": [],
     "values": [
       "bottom",
       "center",
       "inherit",
       "initial",
-      "left",
-      "right",
       "top",
       "unset"
     ]
   },
   "background-repeat": {
     "isInherited": false,
     "subproperties": [
       "background-repeat"
@@ -3431,32 +3542,36 @@ exports.CSS_PROPERTIES = {
   },
   "background-size": {
     "isInherited": false,
     "subproperties": [
       "background-size"
     ],
     "supports": [],
     "values": [
+      "auto",
       "contain",
       "cover",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "block-size": {
     "isInherited": false,
     "subproperties": [
       "block-size"
     ],
     "supports": [],
     "values": [
+      "-moz-available",
+      "-moz-fit-content",
+      "-moz-max-content",
+      "-moz-min-content",
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "border": {
     "isInherited": false,
     "subproperties": [
@@ -3478,70 +3593,52 @@ exports.CSS_PROPERTIES = {
       "border-image-outset",
       "border-image-repeat"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "-moz-element",
-      "-moz-image-rect",
-      "-moz-linear-gradient",
-      "-moz-radial-gradient",
-      "-moz-repeating-linear-gradient",
-      "-moz-repeating-radial-gradient",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
-      "fill",
       "groove",
       "hidden",
       "hsl",
       "hsla",
       "inherit",
       "initial",
       "inset",
-      "linear-gradient",
       "medium",
       "none",
       "outset",
-      "radial-gradient",
-      "repeat",
-      "repeating-linear-gradient",
-      "repeating-radial-gradient",
       "rgb",
       "rgba",
       "ridge",
-      "round",
       "solid",
-      "space",
-      "stretch",
       "thick",
       "thin",
       "transparent",
-      "unset",
-      "url"
+      "unset"
     ]
   },
   "border-block-end": {
     "isInherited": false,
     "subproperties": [
       "border-block-end-width",
       "border-block-end-style",
       "border-block-end-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -3606,17 +3703,16 @@ exports.CSS_PROPERTIES = {
   },
   "border-block-end-width": {
     "isInherited": false,
     "subproperties": [
       "border-block-end-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -3627,17 +3723,16 @@ exports.CSS_PROPERTIES = {
       "border-block-start-style",
       "border-block-start-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -3702,17 +3797,16 @@ exports.CSS_PROPERTIES = {
   },
   "border-block-start-width": {
     "isInherited": false,
     "subproperties": [
       "border-block-start-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -3723,17 +3817,16 @@ exports.CSS_PROPERTIES = {
       "border-bottom-style",
       "border-bottom-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -3822,17 +3915,16 @@ exports.CSS_PROPERTIES = {
   },
   "border-bottom-width": {
     "isInherited": false,
     "subproperties": [
       "border-bottom-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -3888,16 +3980,22 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
+      "auto",
       "fill",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
       "repeat",
       "repeating-linear-gradient",
@@ -3960,16 +4058,21 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
       "unset",
@@ -3978,16 +4081,17 @@ exports.CSS_PROPERTIES = {
   },
   "border-image-width": {
     "isInherited": false,
     "subproperties": [
       "border-image-width"
     ],
     "supports": [],
     "values": [
+      "auto",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "border-inline-end": {
     "isInherited": false,
     "subproperties": [
@@ -3995,17 +4099,16 @@ exports.CSS_PROPERTIES = {
       "border-inline-end-style",
       "border-inline-end-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -4070,17 +4173,16 @@ exports.CSS_PROPERTIES = {
   },
   "border-inline-end-width": {
     "isInherited": false,
     "subproperties": [
       "border-inline-end-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -4091,17 +4193,16 @@ exports.CSS_PROPERTIES = {
       "border-inline-start-style",
       "border-inline-start-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -4166,17 +4267,16 @@ exports.CSS_PROPERTIES = {
   },
   "border-inline-start-width": {
     "isInherited": false,
     "subproperties": [
       "border-inline-start-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -4187,17 +4287,16 @@ exports.CSS_PROPERTIES = {
       "border-left-style",
       "border-left-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -4262,17 +4361,16 @@ exports.CSS_PROPERTIES = {
   },
   "border-left-width": {
     "isInherited": false,
     "subproperties": [
       "border-left-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -4298,17 +4396,16 @@ exports.CSS_PROPERTIES = {
       "border-right-style",
       "border-right-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -4373,17 +4470,16 @@ exports.CSS_PROPERTIES = {
   },
   "border-right-width": {
     "isInherited": false,
     "subproperties": [
       "border-right-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -4431,17 +4527,16 @@ exports.CSS_PROPERTIES = {
       "border-top-style",
       "border-top-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -4530,17 +4625,16 @@ exports.CSS_PROPERTIES = {
   },
   "border-top-width": {
     "isInherited": false,
     "subproperties": [
       "border-top-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -4549,34 +4643,32 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "border-top-width",
       "border-right-width",
       "border-bottom-width",
       "border-left-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
   "bottom": {
     "isInherited": false,
     "subproperties": [
       "bottom"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "box-decoration-break": {
     "isInherited": false,
     "subproperties": [
@@ -4596,17 +4688,16 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "box-shadow"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "hsl",
       "hsla",
       "inherit",
       "initial",
       "inset",
       "none",
       "rgb",
@@ -4834,17 +4925,16 @@ exports.CSS_PROPERTIES = {
   },
   "column-gap": {
     "isInherited": false,
     "subproperties": [
       "column-gap"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "column-rule": {
     "isInherited": false,
@@ -4853,17 +4943,16 @@ exports.CSS_PROPERTIES = {
       "column-rule-style",
       "column-rule-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
       "hidden",
       "hsl",
       "hsla",
@@ -4928,49 +5017,46 @@ exports.CSS_PROPERTIES = {
   },
   "column-rule-width": {
     "isInherited": false,
     "subproperties": [
       "column-rule-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
   "column-width": {
     "isInherited": false,
     "subproperties": [
       "column-width"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "columns": {
     "isInherited": false,
     "subproperties": [
       "column-count",
       "column-width"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "content": {
     "isInherited": false,
     "subproperties": [
@@ -5022,16 +5108,20 @@ exports.CSS_PROPERTIES = {
   },
   "cursor": {
     "isInherited": true,
     "subproperties": [
       "cursor"
     ],
     "supports": [],
     "values": [
+      "-moz-grab",
+      "-moz-grabbing",
+      "-moz-zoom-in",
+      "-moz-zoom-out",
       "alias",
       "all-scroll",
       "auto",
       "cell",
       "col-resize",
       "context-menu",
       "copy",
       "crosshair",
@@ -5056,16 +5146,17 @@ exports.CSS_PROPERTIES = {
       "pointer",
       "progress",
       "row-resize",
       "s-resize",
       "se-resize",
       "sw-resize",
       "text",
       "unset",
+      "url",
       "vertical-text",
       "w-resize",
       "wait",
       "zoom-in",
       "zoom-out"
     ]
   },
   "direction": {
@@ -5177,21 +5268,30 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "fill"
     ],
     "supports": [
       2
     ],
     "values": [
+      "COLOR",
       "context-fill",
       "context-stroke",
-      "inherit",
-      "initial",
-      "unset"
+      "currentColor",
+      "hsl",
+      "hsla",
+      "inherit",
+      "initial",
+      "none",
+      "rgb",
+      "rgba",
+      "transparent",
+      "unset",
+      "url"
     ]
   },
   "fill-opacity": {
     "isInherited": true,
     "subproperties": [
       "fill-opacity"
     ],
     "supports": [],
@@ -5219,36 +5319,47 @@ exports.CSS_PROPERTIES = {
   },
   "filter": {
     "isInherited": false,
     "subproperties": [
       "filter"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
-      "unset"
+      "blur",
+      "brightness",
+      "contrast",
+      "drop-shadow",
+      "grayscale",
+      "hue-rotate",
+      "inherit",
+      "initial",
+      "invert",
+      "none",
+      "opacity",
+      "saturate",
+      "sepia",
+      "unset",
+      "url"
     ]
   },
   "flex": {
     "isInherited": false,
     "subproperties": [
       "flex-grow",
       "flex-shrink",
       "flex-basis"
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "content",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "flex-basis": {
     "isInherited": false,
@@ -5257,17 +5368,16 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "content",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "flex-direction": {
     "isInherited": false,
@@ -5413,88 +5523,56 @@ exports.CSS_PROPERTIES = {
       "font-variant-caps",
       "font-variant-east-asian",
       "font-variant-ligatures",
       "font-variant-numeric",
       "font-variant-position"
     ],
     "supports": [],
     "values": [
-      "-moz-block-height",
       "-moz-button",
       "-moz-desktop",
       "-moz-dialog",
       "-moz-document",
       "-moz-field",
       "-moz-info",
       "-moz-list",
       "-moz-pull-down-menu",
       "-moz-window",
       "-moz-workspace",
       "all-petite-caps",
       "all-small-caps",
-      "auto",
       "bold",
       "bolder",
-      "calc",
       "caption",
-      "common-ligatures",
       "condensed",
-      "contextual",
-      "diagonal-fractions",
-      "discretionary-ligatures",
       "expanded",
       "extra-condensed",
       "extra-expanded",
-      "full-width",
-      "historical-forms",
-      "historical-ligatures",
       "icon",
       "inherit",
       "initial",
       "italic",
-      "jis04",
-      "jis78",
-      "jis83",
-      "jis90",
       "large",
       "larger",
       "lighter",
-      "lining-nums",
       "medium",
       "menu",
       "message-box",
-      "no-common-ligatures",
-      "no-contextual",
-      "no-discretionary-ligatures",
-      "no-historical-ligatures",
-      "none",
       "normal",
       "oblique",
-      "oldstyle-nums",
-      "ordinal",
       "petite-caps",
-      "proportional-nums",
-      "proportional-width",
-      "ruby",
       "semi-condensed",
       "semi-expanded",
-      "simplified",
-      "slashed-zero",
       "small",
       "small-caps",
       "small-caption",
       "smaller",
-      "stacked-fractions",
       "status-bar",
-      "sub",
-      "super",
-      "tabular-nums",
       "titling-caps",
-      "traditional",
       "ultra-condensed",
       "ultra-expanded",
       "unicase",
       "unset",
       "x-large",
       "x-small",
       "xx-large",
       "xx-small"
@@ -5516,16 +5594,17 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "font-feature-settings"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
+      "normal",
       "unset"
     ]
   },
   "font-kerning": {
     "isInherited": true,
     "subproperties": [
       "font-kerning"
     ],
@@ -5568,17 +5647,16 @@ exports.CSS_PROPERTIES = {
   },
   "font-size": {
     "isInherited": true,
     "subproperties": [
       "font-size"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "large",
       "larger",
       "medium",
       "small",
       "smaller",
       "unset",
@@ -5660,16 +5738,18 @@ exports.CSS_PROPERTIES = {
       "font-variant-ligatures",
       "font-variant-numeric",
       "font-variant-position"
     ],
     "supports": [],
     "values": [
       "all-petite-caps",
       "all-small-caps",
+      "annotation",
+      "character-variant",
       "common-ligatures",
       "contextual",
       "diagonal-fractions",
       "discretionary-ligatures",
       "full-width",
       "historical-forms",
       "historical-ligatures",
       "inherit",
@@ -5678,46 +5758,58 @@ exports.CSS_PROPERTIES = {
       "jis78",
       "jis83",
       "jis90",
       "lining-nums",
       "no-common-ligatures",
       "no-contextual",
       "no-discretionary-ligatures",
       "no-historical-ligatures",
+      "none",
       "normal",
       "oldstyle-nums",
       "ordinal",
+      "ornaments",
       "petite-caps",
       "proportional-nums",
       "proportional-width",
       "ruby",
       "simplified",
       "slashed-zero",
       "small-caps",
       "stacked-fractions",
+      "styleset",
+      "stylistic",
       "sub",
       "super",
+      "swash",
       "tabular-nums",
       "titling-caps",
       "traditional",
       "unicase",
       "unset"
     ]
   },
   "font-variant-alternates": {
     "isInherited": true,
     "subproperties": [
       "font-variant-alternates"
     ],
     "supports": [],
     "values": [
+      "annotation",
+      "character-variant",
       "historical-forms",
       "inherit",
       "initial",
+      "normal",
+      "ornaments",
+      "styleset",
+      "stylistic",
+      "swash",
       "unset"
     ]
   },
   "font-variant-caps": {
     "isInherited": true,
     "subproperties": [
       "font-variant-caps"
     ],
@@ -5744,16 +5836,17 @@ exports.CSS_PROPERTIES = {
     "values": [
       "full-width",
       "inherit",
       "initial",
       "jis04",
       "jis78",
       "jis83",
       "jis90",
+      "normal",
       "proportional-width",
       "ruby",
       "simplified",
       "traditional",
       "unset"
     ]
   },
   "font-variant-ligatures": {
@@ -5768,30 +5861,33 @@ exports.CSS_PROPERTIES = {
       "discretionary-ligatures",
       "historical-ligatures",
       "inherit",
       "initial",
       "no-common-ligatures",
       "no-contextual",
       "no-discretionary-ligatures",
       "no-historical-ligatures",
+      "none",
+      "normal",
       "unset"
     ]
   },
   "font-variant-numeric": {
     "isInherited": true,
     "subproperties": [
       "font-variant-numeric"
     ],
     "supports": [],
     "values": [
       "diagonal-fractions",
       "inherit",
       "initial",
       "lining-nums",
+      "normal",
       "oldstyle-nums",
       "ordinal",
       "proportional-nums",
       "slashed-zero",
       "stacked-fractions",
       "tabular-nums",
       "unset"
     ]
@@ -5815,16 +5911,17 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "font-variation-settings"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
+      "normal",
       "unset"
     ]
   },
   "font-weight": {
     "isInherited": true,
     "subproperties": [
       "font-weight"
     ],
@@ -5842,17 +5939,16 @@ exports.CSS_PROPERTIES = {
   "gap": {
     "isInherited": false,
     "subproperties": [
       "row-gap",
       "column-gap"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "grid": {
     "isInherited": false,
@@ -5861,22 +5957,27 @@ exports.CSS_PROPERTIES = {
       "grid-template-rows",
       "grid-template-columns",
       "grid-auto-flow",
       "grid-auto-rows",
       "grid-auto-columns"
     ],
     "supports": [],
     "values": [
+      "auto",
       "column",
       "dense",
+      "fit-content",
       "inherit",
       "initial",
       "max-content",
       "min-content",
+      "minmax",
+      "none",
+      "repeat",
       "row",
       "unset"
     ]
   },
   "grid-area": {
     "isInherited": false,
     "subproperties": [
       "grid-row-start",
@@ -5893,20 +5994,23 @@ exports.CSS_PROPERTIES = {
   },
   "grid-auto-columns": {
     "isInherited": false,
     "subproperties": [
       "grid-auto-columns"
     ],
     "supports": [],
     "values": [
+      "auto",
+      "fit-content",
       "inherit",
       "initial",
       "max-content",
       "min-content",
+      "minmax",
       "unset"
     ]
   },
   "grid-auto-flow": {
     "isInherited": false,
     "subproperties": [
       "grid-auto-flow"
     ],
@@ -5922,20 +6026,23 @@ exports.CSS_PROPERTIES = {
   },
   "grid-auto-rows": {
     "isInherited": false,
     "subproperties": [
       "grid-auto-rows"
     ],
     "supports": [],
     "values": [
+      "auto",
+      "fit-content",
       "inherit",
       "initial",
       "max-content",
       "min-content",
+      "minmax",
       "unset"
     ]
   },
   "grid-column": {
     "isInherited": false,
     "subproperties": [
       "grid-column-start",
       "grid-column-end"
@@ -5961,17 +6068,16 @@ exports.CSS_PROPERTIES = {
   },
   "grid-column-gap": {
     "isInherited": false,
     "subproperties": [
       "column-gap"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "grid-column-start": {
     "isInherited": false,
@@ -5988,17 +6094,16 @@ exports.CSS_PROPERTIES = {
   "grid-gap": {
     "isInherited": false,
     "subproperties": [
       "row-gap",
       "column-gap"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "grid-row": {
     "isInherited": false,
@@ -6027,17 +6132,16 @@ exports.CSS_PROPERTIES = {
   },
   "grid-row-gap": {
     "isInherited": false,
     "subproperties": [
       "row-gap"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "grid-row-start": {
     "isInherited": false,
@@ -6055,76 +6159,91 @@ exports.CSS_PROPERTIES = {
     "isInherited": false,
     "subproperties": [
       "grid-template-areas",
       "grid-template-rows",
       "grid-template-columns"
     ],
     "supports": [],
     "values": [
+      "auto",
+      "fit-content",
       "inherit",
       "initial",
       "max-content",
       "min-content",
+      "minmax",
+      "none",
+      "repeat",
       "unset"
     ]
   },
   "grid-template-areas": {
     "isInherited": false,
     "subproperties": [
       "grid-template-areas"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
+      "none",
       "unset"
     ]
   },
   "grid-template-columns": {
     "isInherited": false,
     "subproperties": [
       "grid-template-columns"
     ],
     "supports": [],
     "values": [
+      "auto",
+      "fit-content",
       "inherit",
       "initial",
       "max-content",
       "min-content",
+      "minmax",
+      "none",
+      "repeat",
       "unset"
     ]
   },
   "grid-template-rows": {
     "isInherited": false,
     "subproperties": [
       "grid-template-rows"
     ],
     "supports": [],
     "values": [
+      "auto",
+      "fit-content",
       "inherit",
       "initial",
       "max-content",
       "min-content",
+      "minmax",
+      "none",
+      "repeat",
       "unset"
     ]
   },
   "height": {
     "isInherited": false,
     "subproperties": [
       "height"
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "hyphens": {
     "isInherited": true,
     "subproperties": [
@@ -6194,17 +6313,16 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "isolation": {
     "isInherited": false,
     "subproperties": [
@@ -6221,109 +6339,113 @@ exports.CSS_PROPERTIES = {
   },
   "justify-content": {
     "isInherited": false,
     "subproperties": [
       "justify-content"
     ],
     "supports": [],
     "values": [
-      "baseline",
       "center",
       "end",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
-      "last baseline",
       "left",
       "normal",
       "right",
+      "safe",
       "space-around",
       "space-between",
       "space-evenly",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "justify-items": {
     "isInherited": false,
     "subproperties": [
       "justify-items"
     ],
     "supports": [],
     "values": [
-      "auto",
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
       "left",
+      "legacy",
       "normal",
       "right",
+      "safe",
       "self-end",
       "self-start",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "justify-self": {
     "isInherited": false,
     "subproperties": [
       "justify-self"
     ],
     "supports": [],
     "values": [
       "auto",
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
       "left",
       "normal",
       "right",
+      "safe",
       "self-end",
       "self-start",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "left": {
     "isInherited": false,
     "subproperties": [
       "left"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "letter-spacing": {
     "isInherited": true,
     "subproperties": [
       "letter-spacing"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "lighting-color": {
     "isInherited": false,
@@ -6349,17 +6471,16 @@ exports.CSS_PROPERTIES = {
   "line-height": {
     "isInherited": true,
     "subproperties": [
       "line-height"
     ],
     "supports": [],
     "values": [
       "-moz-block-height",
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "list-style": {
     "isInherited": true,
@@ -6538,129 +6659,120 @@ exports.CSS_PROPERTIES = {
       "margin-top",
       "margin-right",
       "margin-bottom",
       "margin-left"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "margin-block-end": {
     "isInherited": false,
     "subproperties": [
       "margin-block-end"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "margin-block-start": {
     "isInherited": false,
     "subproperties": [
       "margin-block-start"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "margin-bottom": {
     "isInherited": false,
     "subproperties": [
       "margin-bottom"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "margin-inline-end": {
     "isInherited": false,
     "subproperties": [
       "margin-inline-end"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "margin-inline-start": {
     "isInherited": false,
     "subproperties": [
       "margin-inline-start"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "margin-left": {
     "isInherited": false,
     "subproperties": [
       "margin-left"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "margin-right": {
     "isInherited": false,
     "subproperties": [
       "margin-right"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "margin-top": {
     "isInherited": false,
     "subproperties": [
       "margin-top"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "marker": {
     "isInherited": true,
     "subproperties": [
@@ -6737,18 +6849,24 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
       "add",
       "alpha",
+      "auto",
       "border-box",
       "bottom",
       "center",
       "contain",
       "content-box",
       "cover",
       "exclude",
       "fill-box",
@@ -6825,16 +6943,21 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "-moz-element",
       "-moz-image-rect",
       "-moz-linear-gradient",
       "-moz-radial-gradient",
       "-moz-repeating-linear-gradient",
       "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
       "inherit",
       "initial",
       "linear-gradient",
       "none",
       "radial-gradient",
       "repeating-linear-gradient",
       "repeating-radial-gradient",
       "unset",
@@ -6894,39 +7017,35 @@ exports.CSS_PROPERTIES = {
   },
   "mask-position-x": {
     "isInherited": false,
     "subproperties": [
       "mask-position-x"
     ],
     "supports": [],
     "values": [
-      "bottom",
       "center",
       "inherit",
       "initial",
       "left",
       "right",
-      "top",
       "unset"
     ]
   },
   "mask-position-y": {
     "isInherited": false,
     "subproperties": [
       "mask-position-y"
     ],
     "supports": [],
     "values": [
       "bottom",
       "center",
       "inherit",
       "initial",
-      "left",
-      "right",
       "top",
       "unset"
     ]
   },
   "mask-repeat": {
     "isInherited": false,
     "subproperties": [
       "mask-repeat"
@@ -6946,16 +7065,17 @@ exports.CSS_PROPERTIES = {
   },
   "mask-size": {
     "isInherited": false,
     "subproperties": [
       "mask-size"
     ],
     "supports": [],
     "values": [
+      "auto",
       "contain",
       "cover",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "mask-type": {
@@ -6974,17 +7094,20 @@ exports.CSS_PROPERTIES = {
   },
   "max-block-size": {
     "isInherited": false,
     "subproperties": [
       "max-block-size"
     ],
     "supports": [],
     "values": [
-      "calc",
+      "-moz-available",
+      "-moz-fit-content",
+      "-moz-max-content",
+      "-moz-min-content",
       "inherit",
       "initial",
       "none",
       "unset"
     ]
   },
   "max-height": {
     "isInherited": false,
@@ -6992,17 +7115,16 @@ exports.CSS_PROPERTIES = {
       "max-height"
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
-      "calc",
       "inherit",
       "initial",
       "none",
       "unset"
     ]
   },
   "max-inline-size": {
     "isInherited": false,
@@ -7010,17 +7132,16 @@ exports.CSS_PROPERTIES = {
       "max-inline-size"
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
-      "calc",
       "inherit",
       "initial",
       "none",
       "unset"
     ]
   },
   "max-width": {
     "isInherited": false,
@@ -7028,32 +7149,34 @@ exports.CSS_PROPERTIES = {
       "max-width"
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
-      "calc",
       "inherit",
       "initial",
       "none",
       "unset"
     ]
   },
   "min-block-size": {
     "isInherited": false,
     "subproperties": [
       "min-block-size"
     ],
     "supports": [],
     "values": [
+      "-moz-available",
+      "-moz-fit-content",
+      "-moz-max-content",
+      "-moz-min-content",
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "min-height": {
     "isInherited": false,
     "subproperties": [
@@ -7061,17 +7184,16 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "min-inline-size": {
     "isInherited": false,
     "subproperties": [
@@ -7079,17 +7201,16 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "min-width": {
     "isInherited": false,
     "subproperties": [
@@ -7097,17 +7218,16 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "mix-blend-mode": {
     "isInherited": false,
     "subproperties": [
@@ -7156,17 +7276,16 @@ exports.CSS_PROPERTIES = {
   "object-position": {
     "isInherited": false,
     "subproperties": [
       "object-position"
     ],
     "supports": [],
     "values": [
       "bottom",
-      "calc",
       "center",
       "inherit",
       "initial",
       "left",
       "right",
       "top",
       "unset"
     ]
@@ -7174,59 +7293,55 @@ exports.CSS_PROPERTIES = {
   "offset-block-end": {
     "isInherited": false,
     "subproperties": [
       "offset-block-end"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "offset-block-start": {
     "isInherited": false,
     "subproperties": [
       "offset-block-start"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "offset-inline-end": {
     "isInherited": false,
     "subproperties": [
       "offset-inline-end"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "offset-inline-start": {
     "isInherited": false,
     "subproperties": [
       "offset-inline-start"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "opacity": {
     "isInherited": false,
     "subproperties": [
@@ -7259,22 +7374,22 @@ exports.CSS_PROPERTIES = {
       "outline-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
       "auto",
-      "calc",
       "currentColor",
       "dashed",
       "dotted",
       "double",
       "groove",
+      "hidden",
       "hsl",
       "hsla",
       "inherit",
       "initial",
       "inset",
       "medium",
       "none",
       "outset",
@@ -7311,17 +7426,16 @@ exports.CSS_PROPERTIES = {
   },
   "outline-offset": {
     "isInherited": false,
     "subproperties": [
       "outline-offset"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "outline-style": {
     "isInherited": false,
     "subproperties": [
@@ -7329,16 +7443,17 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [],
     "values": [
       "auto",
       "dashed",
       "dotted",
       "double",
       "groove",
+      "hidden",
       "inherit",
       "initial",
       "inset",
       "none",
       "outset",
       "ridge",
       "solid",
       "unset"
@@ -7346,17 +7461,16 @@ exports.CSS_PROPERTIES = {
   },
   "outline-width": {
     "isInherited": false,
     "subproperties": [
       "outline-width"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "medium",
       "thick",
       "thin",
       "unset"
     ]
   },
@@ -7477,121 +7591,112 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "padding-top",
       "padding-right",
       "padding-bottom",
       "padding-left"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "padding-block-end": {
     "isInherited": false,
     "subproperties": [
       "padding-block-end"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "padding-block-start": {
     "isInherited": false,
     "subproperties": [
       "padding-block-start"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "padding-bottom": {
     "isInherited": false,
     "subproperties": [
       "padding-bottom"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "padding-inline-end": {
     "isInherited": false,
     "subproperties": [
       "padding-inline-end"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "padding-inline-start": {
     "isInherited": false,
     "subproperties": [
       "padding-inline-start"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "padding-left": {
     "isInherited": false,
     "subproperties": [
       "padding-left"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "padding-right": {
     "isInherited": false,
     "subproperties": [
       "padding-right"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "padding-top": {
     "isInherited": false,
     "subproperties": [
       "padding-top"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "page-break-after": {
     "isInherited": false,
     "subproperties": [
@@ -7668,17 +7773,16 @@ exports.CSS_PROPERTIES = {
   "perspective-origin": {
     "isInherited": false,
     "subproperties": [
       "perspective-origin"
     ],
     "supports": [],
     "values": [
       "bottom",
-      "calc",
       "center",
       "inherit",
       "initial",
       "left",
       "right",
       "top",
       "unset"
     ]
@@ -7689,83 +7793,92 @@ exports.CSS_PROPERTIES = {
       "align-content",
       "justify-content"
     ],
     "supports": [],
     "values": [
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
       "left",
       "normal",
       "right",
+      "safe",
       "space-around",
       "space-between",
       "space-evenly",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "place-items": {
     "isInherited": false,
     "subproperties": [
       "align-items",
       "justify-items"
     ],
     "supports": [],
     "values": [
-      "auto",
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
       "left",
+      "legacy",
       "normal",
       "right",
+      "safe",
       "self-end",
       "self-start",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "place-self": {
     "isInherited": false,
     "subproperties": [
       "align-self",
       "justify-self"
     ],
     "supports": [],
     "values": [
       "auto",
       "baseline",
       "center",
       "end",
+      "first baseline",
       "flex-end",
       "flex-start",
       "inherit",
       "initial",
       "last baseline",
       "left",
       "normal",
       "right",
+      "safe",
       "self-end",
       "self-start",
       "start",
       "stretch",
+      "unsafe",
       "unset"
     ]
   },
   "pointer-events": {
     "isInherited": true,
     "subproperties": [
       "pointer-events"
     ],
@@ -7835,30 +7948,28 @@ exports.CSS_PROPERTIES = {
   "right": {
     "isInherited": false,
     "subproperties": [
       "right"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "row-gap": {
     "isInherited": false,
     "subproperties": [
       "row-gap"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "ruby-align": {
     "isInherited": true,
@@ -7911,16 +8022,17 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [],
     "values": [
       "bottom",
       "center",
       "inherit",
       "initial",
       "left",
+      "none",
       "right",
       "top",
       "unset"
     ]
   },
   "scroll-snap-destination": {
     "isInherited": false,
     "subproperties": [
@@ -7942,28 +8054,32 @@ exports.CSS_PROPERTIES = {
     "isInherited": false,
     "subproperties": [
       "scroll-snap-points-x"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
+      "none",
+      "repeat",
       "unset"
     ]
   },
   "scroll-snap-points-y": {
     "isInherited": false,
     "subproperties": [
       "scroll-snap-points-y"
     ],
     "supports": [],
     "values": [
       "inherit",
       "initial",
+      "none",
+      "repeat",
       "unset"
     ]
   },
   "scroll-snap-type": {
     "isInherited": false,
     "subproperties": [
       "scroll-snap-type-x",
       "scroll-snap-type-y"
@@ -8022,34 +8138,58 @@ exports.CSS_PROPERTIES = {
   },
   "shape-margin": {
     "isInherited": false,
     "subproperties": [
       "shape-margin"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "shape-outside": {
     "isInherited": false,
     "subproperties": [
       "shape-outside"
     ],
     "supports": [
       4
     ],
     "values": [
-      "inherit",
-      "initial",
-      "unset"
+      "-moz-element",
+      "-moz-image-rect",
+      "-moz-linear-gradient",
+      "-moz-radial-gradient",
+      "-moz-repeating-linear-gradient",
+      "-moz-repeating-radial-gradient",
+      "-webkit-gradient",
+      "-webkit-linear-gradient",
+      "-webkit-radial-gradient",
+      "-webkit-repeating-linear-gradient",
+      "-webkit-repeating-radial-gradient",
+      "border-box",
+      "circle",
+      "content-box",
+      "ellipse",
+      "inherit",
+      "initial",
+      "inset",
+      "linear-gradient",
+      "margin-box",
+      "none",
+      "padding-box",
+      "polygon",
+      "radial-gradient",
+      "repeating-linear-gradient",
+      "repeating-radial-gradient",
+      "unset",
+      "url"
     ]
   },
   "shape-rendering": {
     "isInherited": true,
     "subproperties": [
       "shape-rendering"
     ],
     "supports": [],
@@ -8100,33 +8240,43 @@ exports.CSS_PROPERTIES = {
     "isInherited": true,
     "subproperties": [
       "stroke"
     ],
     "supports": [
       2
     ],
     "values": [
+      "COLOR",
       "context-fill",
       "context-stroke",
-      "inherit",
-      "initial",
-      "unset"
+      "currentColor",
+      "hsl",
+      "hsla",
+      "inherit",
+      "initial",
+      "none",
+      "rgb",
+      "rgba",
+      "transparent",
+      "unset",
+      "url"
     ]
   },
   "stroke-dasharray": {
     "isInherited": true,
     "subproperties": [
       "stroke-dasharray"
     ],
     "supports": [],
     "values": [
       "context-value",
       "inherit",
       "initial",
+      "none",
       "unset"
     ]
   },
   "stroke-dashoffset": {
     "isInherited": true,
     "subproperties": [
       "stroke-dashoffset"
     ],
@@ -8280,17 +8430,16 @@ exports.CSS_PROPERTIES = {
   "text-combine-upright": {
     "isInherited": true,
     "subproperties": [
       "text-combine-upright"
     ],
     "supports": [],
     "values": [
       "all",
-      "digits",
       "inherit",
       "initial",
       "none",
       "unset"
     ]
   },
   "text-decoration": {
     "isInherited": false,
@@ -8388,24 +8537,32 @@ exports.CSS_PROPERTIES = {
       "text-emphasis-style",
       "text-emphasis-color"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
+      "circle",
       "currentColor",
+      "dot",
+      "double-circle",
+      "filled",
       "hsl",
       "hsla",
       "inherit",
       "initial",
+      "none",
+      "open",
       "rgb",
       "rgba",
+      "sesame",
       "transparent",
+      "triangle",
       "unset"
     ]
   },
   "text-emphasis-color": {
     "isInherited": true,
     "subproperties": [
       "text-emphasis-color"
     ],
@@ -8443,29 +8600,36 @@ exports.CSS_PROPERTIES = {
   },
   "text-emphasis-style": {
     "isInherited": true,
     "subproperties": [
       "text-emphasis-style"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "circle",
+      "dot",
+      "double-circle",
+      "filled",
+      "inherit",
+      "initial",
+      "none",
+      "open",
+      "sesame",
+      "triangle",
       "unset"
     ]
   },
   "text-indent": {
     "isInherited": true,
     "subproperties": [
       "text-indent"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "text-justify": {
     "isInherited": true,
     "subproperties": [
@@ -8534,17 +8698,16 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "text-shadow"
     ],
     "supports": [
       2
     ],
     "values": [
       "COLOR",
-      "calc",
       "currentColor",
       "hsl",
       "hsla",
       "inherit",
       "initial",
       "none",
       "rgb",
       "rgba",
@@ -8572,17 +8735,16 @@ exports.CSS_PROPERTIES = {
   "top": {
     "isInherited": false,
     "subproperties": [
       "top"
     ],
     "supports": [],
     "values": [
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "touch-action": {
     "isInherited": false,
     "subproperties": [
@@ -8602,18 +8764,42 @@ exports.CSS_PROPERTIES = {
   },
   "transform": {
     "isInherited": false,
     "subproperties": [
       "transform"
     ],
     "supports": [],
     "values": [
-      "inherit",
-      "initial",
+      "accumulatematrix",
+      "inherit",
+      "initial",
+      "interpolatematrix",
+      "matrix",
+      "matrix3d",
+      "none",
+      "perspective",
+      "rotate",
+      "rotate3d",
+      "rotateX",
+      "rotateY",
+      "rotateZ",
+      "scale",
+      "scale3d",
+      "scaleX",
+      "scaleY",
+      "scaleZ",
+      "skew",
+      "skewX",
+      "skewY",
+      "translate",
+      "translate3d",
+      "translateX",
+      "translateY",
+      "translateZ",
       "unset"
     ]
   },
   "transform-box": {
     "isInherited": false,
     "subproperties": [
       "transform-box"
     ],
@@ -8671,16 +8857,17 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "all",
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
+      "frames",
       "inherit",
       "initial",
       "linear",
       "none",
       "step-end",
       "step-start",
       "steps",
       "unset"
@@ -8733,16 +8920,17 @@ exports.CSS_PROPERTIES = {
       10
     ],
     "values": [
       "cubic-bezier",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
+      "frames",
       "inherit",
       "initial",
       "linear",
       "step-end",
       "step-start",
       "steps",
       "unset"
     ]
@@ -8784,17 +8972,16 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "vertical-align"
     ],
     "supports": [],
     "values": [
       "-moz-middle-with-baseline",
       "baseline",
       "bottom",
-      "calc",
       "inherit",
       "initial",
       "middle",
       "sub",
       "super",
       "text-bottom",
       "text-top",
       "top",
@@ -8841,29 +9028,29 @@ exports.CSS_PROPERTIES = {
     ],
     "supports": [],
     "values": [
       "-moz-available",
       "-moz-fit-content",
       "-moz-max-content",
       "-moz-min-content",
       "auto",
-      "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "will-change": {
     "isInherited": false,
     "subproperties": [
       "will-change"
     ],
     "supports": [],
     "values": [
+      "auto",
       "inherit",
       "initial",
       "unset"
     ]
   },
   "word-break": {
     "isInherited": true,
     "subproperties": [
@@ -8881,17 +9068,16 @@ exports.CSS_PROPERTIES = {
   },
   "word-spacing": {
     "isInherited": true,
     "subproperties": [
       "word-spacing"
     ],
     "supports": [],
     "values": [
-      "calc",
       "inherit",
       "initial",
       "normal",
       "unset"
     ]
   },
   "word-wrap": {
     "isInherited": true,
--- a/devtools/shared/gcli/commands/screenshot.js
+++ b/devtools/shared/gcli/commands/screenshot.js
@@ -486,25 +486,19 @@ function DownloadListener(win, transfer)
   }
 
   // Allow saveToFile to await completion for error handling
   this._completedDeferred = defer();
   this.completed = this._completedDeferred.promise;
 }
 
 DownloadListener.prototype = {
-  QueryInterface: function(iid) {
-    if (iid.equals(Ci.nsIInterfaceRequestor) ||
-        iid.equals(Ci.nsIWebProgressListener) ||
-        iid.equals(Ci.nsIWebProgressListener2) ||
-        iid.equals(Ci.nsISupports)) {
-      return this;
-    }
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIInterfaceRequestor",
+                                          "nsIWebProgressListener",
+                                          "nsIWebProgressListener2"]),
 
   getInterface: function(iid) {
     if (iid.equals(Ci.nsIAuthPrompt) ||
         iid.equals(Ci.nsIAuthPrompt2)) {
       let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]
                  .getService(Ci.nsIPromptFactory);
       return ww.getPrompt(this.window, iid);
     }
--- a/devtools/shared/webconsole/network-monitor.js
+++ b/devtools/shared/webconsole/network-monitor.js
@@ -281,18 +281,17 @@ function NetworkResponseListener(owner, 
   let channel = this.httpActivity.channel;
   this._wrappedNotificationCallbacks = channel.notificationCallbacks;
   channel.notificationCallbacks = this;
 }
 
 NetworkResponseListener.prototype = {
   QueryInterface:
     XPCOMUtils.generateQI([Ci.nsIStreamListener, Ci.nsIInputStreamCallback,
-                           Ci.nsIRequestObserver, Ci.nsIInterfaceRequestor,
-                           Ci.nsISupports]),
+                           Ci.nsIRequestObserver, Ci.nsIInterfaceRequestor]),
 
   // nsIInterfaceRequestor implementation
 
   /**
    * This object implements nsIProgressEventSink, but also needs to forward
    * interface requests to the notification callbacks of other objects.
    */
   getInterface(iid) {
--- a/devtools/shared/webconsole/throttle.js
+++ b/devtools/shared/webconsole/throttle.js
@@ -37,18 +37,17 @@ function NetworkThrottleListener(queue) 
   this.pendingException = null;
   this.offset = 0;
   this.responseStarted = false;
   this.activities = {};
 }
 
 NetworkThrottleListener.prototype = {
   QueryInterface:
-    XPCOMUtils.generateQI([Ci.nsIStreamListener, Ci.nsIInterfaceRequestor,
-                           Ci.nsISupports]),
+    XPCOMUtils.generateQI([Ci.nsIStreamListener, Ci.nsIInterfaceRequestor]),
 
   /**
    * Set the original listener for this object.  The original listener
    * will receive requests from this object when the queue allows data
    * through.
    *
    * @param {nsIStreamListener} originalListener the original listener
    *        for the channel, to which all requests will be sent
--- a/devtools/startup/aboutdebugging-registration.js
+++ b/devtools/startup/aboutdebugging-registration.js
@@ -16,17 +16,17 @@ const { nsIAboutModule } = Ci;
 function AboutDebugging() {}
 
 AboutDebugging.prototype = {
   uri: Services.io.newURI("chrome://devtools/content/aboutdebugging/aboutdebugging.xhtml"),
   classDescription: "about:debugging",
   classID: Components.ID("1060afaf-dc9e-43da-8646-23a2faf48493"),
   contractID: "@mozilla.org/network/protocol/about;1?what=debugging",
 
-  QueryInterface: XPCOMUtils.generateQI([nsIAboutModule]),
+  QueryInterface: ChromeUtils.generateQI([nsIAboutModule]),
 
   newChannel: function(uri, loadInfo) {
     let chan = Services.io.newChannelFromURIWithLoadInfo(
       this.uri,
       loadInfo
     );
     chan.owner = Services.scriptSecurityManager.getSystemPrincipal();
     return chan;
--- a/devtools/startup/aboutdevtools/aboutdevtools-registration.js
+++ b/devtools/startup/aboutdevtools/aboutdevtools-registration.js
@@ -14,17 +14,17 @@ const { nsIAboutModule } = Ci;
 function AboutDevtools() {}
 
 AboutDevtools.prototype = {
   uri: Services.io.newURI("chrome://devtools-startup/content/aboutdevtools/aboutdevtools.xhtml"),
   classDescription: "about:devtools",
   classID: Components.ID("3a16d383-92bd-4c24-ac10-0e2bd66883ab"),
   contractID: "@mozilla.org/network/protocol/about;1?what=devtools",
 
-  QueryInterface: XPCOMUtils.generateQI([nsIAboutModule]),
+  QueryInterface: ChromeUtils.generateQI([nsIAboutModule]),
 
   newChannel: function(uri, loadInfo) {
     let chan = Services.io.newChannelFromURIWithLoadInfo(
       this.uri,
       loadInfo
     );
     chan.owner = Services.scriptSecurityManager.getSystemPrincipal();
     return chan;
--- a/devtools/startup/aboutdevtoolstoolbox-registration.js
+++ b/devtools/startup/aboutdevtoolstoolbox-registration.js
@@ -15,17 +15,17 @@ const { nsIAboutModule } = Ci;
 function AboutDevtoolsToolbox() {}
 
 AboutDevtoolsToolbox.prototype = {
   uri: Services.io.newURI("chrome://devtools/content/framework/toolbox.xul"),
   classDescription: "about:devtools-toolbox",
   classID: Components.ID("11342911-3135-45a8-8d71-737a2b0ad469"),
   contractID: "@mozilla.org/network/protocol/about;1?what=devtools-toolbox",
 
-  QueryInterface: XPCOMUtils.generateQI([nsIAboutModule]),
+  QueryInterface: ChromeUtils.generateQI([nsIAboutModule]),
 
   newChannel: function(uri, loadInfo) {
     let chan = Services.io.newChannelFromURIWithLoadInfo(this.uri, loadInfo);
     chan.owner = Services.scriptSecurityManager.getSystemPrincipal();
     return chan;
   },
 
   getURIFlags: function(uri) {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9589,19 +9589,21 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       }
       // If we are a noopener load, we just hand the whole thing over to our
       // window.
       if (aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) {
         // Various asserts that we know to hold because NO_OPENER loads can only
         // happen for links.
         MOZ_ASSERT(!aLoadReplace);
         MOZ_ASSERT(aPrincipalToInherit == aTriggeringPrincipal);
-        MOZ_ASSERT(aFlags == INTERNAL_LOAD_FLAGS_NO_OPENER ||
-                   aFlags == (INTERNAL_LOAD_FLAGS_NO_OPENER |
-                              INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
+        MOZ_ASSERT((aFlags & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
+                   INTERNAL_LOAD_FLAGS_NO_OPENER ||
+                   (aFlags & ~INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED) ==
+                   (INTERNAL_LOAD_FLAGS_NO_OPENER |
+                    INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
         MOZ_ASSERT(!aPostData);
         MOZ_ASSERT(!aHeadersData);
         // If OnLinkClickSync was invoked inside the onload handler, the load
         // type would be set to LOAD_NORMAL_REPLACE; otherwise it should be
         // LOAD_LINK.
         MOZ_ASSERT(aLoadType == LOAD_LINK ||
                    aLoadType == LOAD_NORMAL_REPLACE);
         MOZ_ASSERT(!aSHEntry);
@@ -13353,16 +13355,17 @@ public:
   OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
                    nsIURI* aURI,
                    const char16_t* aTargetSpec,
                    const nsAString& aFileName,
                    nsIInputStream* aPostDataStream,
                    int64_t aPostDataStreamLength,
                    nsIInputStream* aHeadersDataStream,
                    bool aNoOpenerImplied,
+                   bool aIsUserTriggered,
                    bool aIsTrusted,
                    nsIPrincipal* aTriggeringPrincipal);
 
   NS_IMETHOD Run() override
   {
     nsAutoPopupStatePusher popupStatePusher(mPopupState);
 
     // We need to set up an AutoJSAPI here for the following reason: When we do
@@ -13371,71 +13374,76 @@ public:
     // So we need to fake things so that we don't look like native code as far
     // as LegacyIsCallerNativeCode() is concerned.
     AutoJSAPI jsapi;
     if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
       mHandler->OnLinkClickSync(mContent, mURI,
                                 mTargetSpec.get(), mFileName,
                                 mPostDataStream, mPostDataStreamLength,
                                 mHeadersDataStream, mNoOpenerImplied,
-                                nullptr, nullptr, mTriggeringPrincipal);
+                                nullptr, nullptr, mIsUserTriggered,
+                                mTriggeringPrincipal);
     }
     return NS_OK;
   }
 
 private:
   RefPtr<nsDocShell> mHandler;
   nsCOMPtr<nsIURI> mURI;
   nsString mTargetSpec;
   nsString mFileName;
   nsCOMPtr<nsIInputStream> mPostDataStream;
   int64_t mPostDataStreamLength;
   nsCOMPtr<nsIInputStream> mHeadersDataStream;
   nsCOMPtr<nsIContent> mContent;
   PopupControlState mPopupState;
   bool mNoOpenerImplied;
+  bool mIsUserTriggered;
   bool mIsTrusted;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
 };
 
 OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
                                    nsIContent* aContent,
                                    nsIURI* aURI,
                                    const char16_t* aTargetSpec,
                                    const nsAString& aFileName,
                                    nsIInputStream* aPostDataStream,
                                    int64_t aPostDataStreamLength,
                                    nsIInputStream* aHeadersDataStream,
                                    bool aNoOpenerImplied,
+                                   bool aIsUserTriggered,
                                    bool aIsTrusted,
                                    nsIPrincipal* aTriggeringPrincipal)
   : mozilla::Runnable("OnLinkClickEvent")
   , mHandler(aHandler)
   , mURI(aURI)
   , mTargetSpec(aTargetSpec)
   , mFileName(aFileName)
   , mPostDataStream(aPostDataStream)
   , mPostDataStreamLength(aPostDataStreamLength)
   , mHeadersDataStream(aHeadersDataStream)
   , mContent(aContent)
   , mPopupState(mHandler->mScriptGlobal->GetPopupControlState())
   , mNoOpenerImplied(aNoOpenerImplied)
+  , mIsUserTriggered(aIsUserTriggered)
   , mIsTrusted(aIsTrusted)
   , mTriggeringPrincipal(aTriggeringPrincipal)
 {
 }
 
 NS_IMETHODIMP
 nsDocShell::OnLinkClick(nsIContent* aContent,
                         nsIURI* aURI,
                         const char16_t* aTargetSpec,
                         const nsAString& aFileName,
                         nsIInputStream* aPostDataStream,
                         int64_t aPostDataStreamLength,
                         nsIInputStream* aHeadersDataStream,
+                        bool aIsUserTriggered,
                         bool aIsTrusted,
                         nsIPrincipal* aTriggeringPrincipal)
 {
   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
 
   if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
     return NS_OK;
   }
@@ -13472,17 +13480,17 @@ nsDocShell::OnLinkClick(nsIContent* aCon
   if (NS_FAILED(rv)) {
     target = aTargetSpec;
   }
 
   nsCOMPtr<nsIRunnable> ev =
     new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName,
                          aPostDataStream, aPostDataStreamLength,
                          aHeadersDataStream, noOpenerImplied,
-                         aIsTrusted, aTriggeringPrincipal);
+                         aIsUserTriggered, aIsTrusted, aTriggeringPrincipal);
   return DispatchToTabGroup(TaskCategory::UI, ev.forget());
 }
 
 static bool
 IsElementAnchorOrArea(nsIContent* aContent)
 {
   // Make sure we are dealing with either an <A> or <AREA> element in the HTML
   // or XHTML namespace.
@@ -13495,16 +13503,17 @@ nsDocShell::OnLinkClickSync(nsIContent* 
                             const char16_t* aTargetSpec,
                             const nsAString& aFileName,
                             nsIInputStream* aPostDataStream,
                             int64_t aPostDataStreamLength,
                             nsIInputStream* aHeadersDataStream,
                             bool aNoOpenerImplied,
                             nsIDocShell** aDocShell,
                             nsIRequest** aRequest,
+                            bool aIsUserTriggered,
                             nsIPrincipal* aTriggeringPrincipal)
 {
   // Initialize the DocShell / Request
   if (aDocShell) {
     *aDocShell = nullptr;
   }
   if (aRequest) {
     *aRequest = nullptr;
@@ -13633,16 +13642,20 @@ nsDocShell::OnLinkClickSync(nsIContent* 
                          : aContent->NodePrincipal();
 
   // Link click (or form submission) can be triggered inside an onload handler,
   // and we don't want to add history entry in this case.
   bool inOnLoadHandler = false;
   GetIsExecutingOnLoadHandler(&inOnLoadHandler);
   uint32_t loadType = inOnLoadHandler ? LOAD_NORMAL_REPLACE : LOAD_LINK;
 
+  if (aIsUserTriggered) {
+    flags |= INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED;
+  }
+
   nsresult rv = InternalLoad(clonedURI,                 // New URI
                              nullptr,                   // Original URI
                              Nothing(),                 // Let the protocol handler assign it
                              false,                     // LoadReplace
                              referer,                   // Referer URI
                              refererPolicy,             // Referer policy
                              triggeringPrincipal,
                              aContent->NodePrincipal(),
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -205,28 +205,30 @@ public:
   // nsILinkHandler
   NS_IMETHOD OnLinkClick(nsIContent* aContent,
                          nsIURI* aURI,
                          const char16_t* aTargetSpec,
                          const nsAString& aFileName,
                          nsIInputStream* aPostDataStream,
                          int64_t aPostDataStreamLength,
                          nsIInputStream* aHeadersDataStream,
+                         bool aIsUserTriggered,
                          bool aIsTrusted,
                          nsIPrincipal* aTriggeringPrincipal) override;
   NS_IMETHOD OnLinkClickSync(nsIContent* aContent,
                              nsIURI* aURI,
                              const char16_t* aTargetSpec,
                              const nsAString& aFileName,
                              nsIInputStream* aPostDataStream = 0,
                              int64_t aPostDataStreamLength = -1,
                              nsIInputStream* aHeadersDataStream = 0,
                              bool aNoOpenerImplied = false,
                              nsIDocShell** aDocShell = 0,
                              nsIRequest** aRequest = 0,
+                             bool aIsUserTriggered = false,
                              nsIPrincipal* aTriggeringPrincipal = nullptr) override;
   NS_IMETHOD OnOverLink(nsIContent* aContent,
                         nsIURI* aURI,
                         const char16_t* aTargetSpec) override;
   NS_IMETHOD OnLeaveLink() override;
 
   // Don't use NS_DECL_NSILOADCONTEXT because some of nsILoadContext's methods
   // are shared with nsIDocShell (appID, etc.) and can't be declared twice.
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -134,16 +134,19 @@ interface nsIDocShell : nsIDocShellTreeI
   // Whether this is the load of a frame's original src attribute
   const long INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC      = 0x80;
 
   const long INTERNAL_LOAD_FLAGS_NO_OPENER               = 0x100;
 
   // Whether a top-level data URI navigation is allowed for that load
   const long INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI    = 0x200;
 
+  // Whether the load was triggered by user interaction.
+  const long INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED       = 0x1000;
+
   /**
    * Loads the given URI.  This method is identical to loadURI(...) except
    * that its parameter list is broken out instead of being packaged inside
    * of an nsIDocShellLoadInfo object...
    *
    * @param aURI                 - The URI to load.
    * @param aOriginalURI         - The URI to set as the originalURI on the channel
    *                               that does the load. If null, aURI will be set as
--- a/docshell/base/nsILinkHandler.h
+++ b/docshell/base/nsILinkHandler.h
@@ -44,16 +44,17 @@ public:
    */
   NS_IMETHOD OnLinkClick(nsIContent* aContent,
                          nsIURI* aURI,
                          const char16_t* aTargetSpec,
                          const nsAString& aFileName,
                          nsIInputStream* aPostDataStream,
                          int64_t aPostDataStreamLength,
                          nsIInputStream* aHeadersDataStream,
+                         bool aIsUserTriggered,
                          bool aIsTrusted,
                          nsIPrincipal* aTriggeringPrincipal) = 0;
 
   /**
    * Process a click on a link.
    *
    * Works the same as OnLinkClick() except it happens immediately rather than
    * through an event.
@@ -77,16 +78,17 @@ public:
                              const char16_t* aTargetSpec,
                              const nsAString& aFileName,
                              nsIInputStream* aPostDataStream = 0,
                              int64_t aPostDataStreamLength = -1,
                              nsIInputStream* aHeadersDataStream = 0,
                              bool aNoOpenerImplied = false,
                              nsIDocShell** aDocShell = 0,
                              nsIRequest** aRequest = 0,
+                             bool aIsUserTriggered = false,
                              nsIPrincipal* aTriggeringPrincipal = nullptr) = 0;
 
   /**
    * Process a mouse-over a link.
    *
    * @param aContent the linked content.
    * @param aURI an URI object that defines the destination for the link
    * @param aTargetSpec indicates where the link is targeted (it may be an empty
--- a/docshell/test/browser/browser_bug655270.js
+++ b/docshell/test/browser/browser_bug655270.js
@@ -48,13 +48,13 @@ function test() {
 
     onBeginUpdateBatch: function() { },
     onEndUpdateBatch: function() { },
     onVisits: function() { },
     onTitleChanged: function() { },
     onDeleteURI: function() { },
     onClearHistory: function() { },
     onDeleteVisits: function() { },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
+    QueryInterface: ChromeUtils.generateQI([Ci.nsINavHistoryObserver])
   };
 
   PlacesUtils.history.addObserver(observer);
 }
--- a/docshell/test/browser/browser_bug670318.js
+++ b/docshell/test/browser/browser_bug670318.js
@@ -46,18 +46,18 @@ add_task(async function test() {
         OnHistoryReplaceEntry: () => {
           // The initial load of about:blank causes a transient entry to be
           // created, so our first navigation to a real page is a replace
           // instead of a new entry.
           ++count;
           return true;
         },
 
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
-                                               Ci.nsISupportsWeakReference])
+        QueryInterface: ChromeUtils.generateQI([Ci.nsISHistoryListener,
+                                                Ci.nsISupportsWeakReference])
       };
 
       history.legacySHistory.addSHistoryListener(listener);
       // Since listener implements nsISupportsWeakReference, we are
       // responsible for keeping it alive so that the GC doesn't clear
       // it before the test completes. We do this by anchoring the listener
       // to the content global window, and clearing it just before the test
       // completes.
--- a/docshell/test/browser/browser_onbeforeunload_navigation.js
+++ b/docshell/test/browser/browser_onbeforeunload_navigation.js
@@ -150,17 +150,17 @@ var tabStateListener = {
     if ((stateFlags & startDocumentFlags) == startDocumentFlags) {
       loadStarted = true;
     }
   },
   onStatusChange: () => {},
   onLocationChange: () => {},
   onSecurityChange: () => {},
   onProgressChange: () => {},
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener])
 };
 
 function onTabModalDialogLoaded(node) {
   let mm = testTab.linkedBrowser.messageManager;
   mm.sendAsyncMessage("test-beforeunload:dialog");
 
   if (gMultiProcessBrowser) {
     // In non-e10s, onTabModalDialogLoaded fires synchronously while
--- a/docshell/test/browser/file_bug1328501_framescript.js
+++ b/docshell/test/browser/file_bug1328501_framescript.js
@@ -9,17 +9,17 @@ let requestObserver = {
       // content viewers being created.
       getChildDocShells().map(ds => {
         let window = ds.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsILoadContext)
                       .associatedWindow;
       });
     }
   },
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIObserver
   ])
 }
 Services.obs.addObserver(requestObserver, "http-on-opening-request");
 addEventListener("unload", e => {
   if (e.target == this) {
     Services.obs.removeObserver(requestObserver, "http-on-opening-request");
   }
--- a/docshell/test/browser/file_bug422543_script.js
+++ b/docshell/test/browser/file_bug422543_script.js
@@ -33,18 +33,18 @@ SHistoryListener.prototype = {
 
   OnHistoryReload: function (aReloadURI, aReloadFlags) {
     this.last = "reload";
     return this.retval;
   },
 
   OnHistoryReplaceEntry: function (aIndex) {},
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
-                                         Ci.nsISupportsWeakReference])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsISHistoryListener,
+                                          Ci.nsISupportsWeakReference])
 };
 
 let testAPI = {
   shistory: null,
   listeners: [ new SHistoryListener(),
                new SHistoryListener() ],
 
   init() {
--- a/docshell/test/chrome/test_bug909218.html
+++ b/docshell/test/chrome/test_bug909218.html
@@ -104,17 +104,17 @@ RequestWatcher = {
     is(req.loadFlags & TEST_FLAGS, TEST_FLAGS, "request " + req.name + " has the expected flags");
     this.requestCounts[req.name] += 1;
     var stopFlags = Ci.nsIWebProgressListener.STATE_STOP |
                     Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
     if (req.name == TEST_URL && (flags & stopFlags) == stopFlags) {
       this.finalize();
     }
   },
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIWebProgressListener,
     Ci.nsISupportsWeakReference,
   ])
 }
 
 function docshellForWindow(win) {
   return win.
          QueryInterface(Ci.nsIInterfaceRequestor).
--- a/docshell/test/chrome/test_viewsource_forbidden_in_iframe.xul
+++ b/docshell/test/chrome/test_viewsource_forbidden_in_iframe.xul
@@ -54,18 +54,18 @@ https://bugzilla.mozilla.org/show_bug.cg
             reject("no network error message found in URI")
             return;
           }
 
           var errorMsg = matchArray[1];
           resolve(decodeURIComponent(errorMsg));
         },
 
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                               Ci.nsISupportsWeakReference])
+        QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                                Ci.nsISupportsWeakReference])
       };
 
       frame.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIWebNavigation)
                          .QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIWebProgress)
                          .addProgressListener(progressListener,
                                               Ci.nsIWebProgress.NOTIFY_LOCATION |
--- a/dom/base/DOMRequestHelper.jsm
+++ b/dom/base/DOMRequestHelper.jsm
@@ -37,18 +37,18 @@ function DOMRequestIpcHelper() {
   this._window = null;
 }
 
 DOMRequestIpcHelper.prototype = {
   /**
    * An object which "inherits" from DOMRequestIpcHelper and declares its own
    * queryInterface method MUST implement Ci.nsISupportsWeakReference.
    */
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
-                                         Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference,
+                                          Ci.nsIObserver]),
 
    /**
    *  'aMessages' is expected to be an array of either:
    *  - objects of this form:
    *    {
    *      name: "messageName",
    *      weakRef: false
    *    }
--- a/dom/base/DirectionalityUtils.cpp
+++ b/dom/base/DirectionalityUtils.cpp
@@ -236,30 +236,31 @@ using mozilla::dom::Element;
 static bool
 DoesNotParticipateInAutoDirection(const Element* aElement)
 {
   mozilla::dom::NodeInfo* nodeInfo = aElement->NodeInfo();
   return (!aElement->IsHTMLElement() ||
           nodeInfo->Equals(nsGkAtoms::script) ||
           nodeInfo->Equals(nsGkAtoms::style) ||
           nodeInfo->Equals(nsGkAtoms::textarea) ||
-          aElement->IsInAnonymousSubtree());
+          (aElement->IsInAnonymousSubtree() && !aElement->HasDirAuto()));
 }
 
 /**
  * Returns true if aElement is one of the element whose text content should not
  * affect the direction of ancestors with dir=auto (though it may affect its own
  * direction, e.g. <bdi>)
  */
 static bool
 DoesNotAffectDirectionOfAncestors(const Element* aElement)
 {
   return (DoesNotParticipateInAutoDirection(aElement) ||
           aElement->IsHTMLElement(nsGkAtoms::bdi) ||
-          aElement->HasFixedDir());
+          aElement->HasFixedDir() ||
+          aElement->IsInAnonymousSubtree());
 }
 
 /**
  * Returns the directionality of a Unicode character
  */
 static Directionality
 GetDirectionFromChar(uint32_t ch)
 {
@@ -275,20 +276,24 @@ GetDirectionFromChar(uint32_t ch)
       return eDir_NotSet;
   }
 }
 
 inline static bool
 NodeAffectsDirAutoAncestor(nsINode* aTextNode)
 {
   Element* parent = aTextNode->GetParentElement();
+  // In the anonymous content, we limit our implementation to only
+  // allow the children text node of the direct dir=auto parent in
+  // the same anonymous subtree to affact the direction.
   return (parent &&
           !DoesNotParticipateInAutoDirection(parent) &&
           parent->NodeOrAncestorHasDirAuto() &&
-          !aTextNode->IsInAnonymousSubtree());
+          (!aTextNode->IsInAnonymousSubtree() ||
+            parent->HasDirAuto()));
 }
 
 Directionality
 GetDirectionFromText(const char16_t* aText, const uint32_t aLength,
                      uint32_t* aFirstStrong)
 {
   const char16_t* start = aText;
   const char16_t* end = aText + aLength;
@@ -915,24 +920,29 @@ SetDirectionFromNewTextNode(nsTextNode* 
   if (dir != eDir_NotSet) {
     SetAncestorDirectionIfAuto(aTextNode, dir);
   }
 }
 
 void
 ResetDirectionSetByTextNode(nsTextNode* aTextNode)
 {
-  if (!NodeAffectsDirAutoAncestor(aTextNode)) {
-    nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode);
+  // We used to check NodeAffectsDirAutoAncestor() in this function, but
+  // stopped doing that since calling IsInAnonymousSubtree()
+  // too late (during nsTextNode::UnbindFromTree) is impossible and this
+  // function was no-op when there's no directionality map.
+  if (!aTextNode->HasTextNodeDirectionalityMap()) {
     return;
   }
 
   Directionality dir = GetDirectionFromText(aTextNode->GetText());
-  if (dir != eDir_NotSet && aTextNode->HasTextNodeDirectionalityMap()) {
+  if (dir != eDir_NotSet) {
     nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode);
+  } else {
+    nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode);
   }
 }
 
 void
 SetDirectionalityFromValue(Element* aElement, const nsAString& value,
                            bool aNotify)
 {
   Directionality dir = GetDirectionFromText(PromiseFlatString(value).get(),
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -1449,21 +1449,17 @@ EventSourceImpl::DispatchCurrentMessageE
   if (message->mEventName.IsEmpty()) {
     message->mEventName.AssignLiteral("message");
   }
 
   if (message->mLastEventID.IsEmpty() && !mLastEventID.IsEmpty()) {
     message->mLastEventID.Assign(mLastEventID);
   }
 
-  size_t sizeBefore = mMessagesToDispatch.GetSize();
   mMessagesToDispatch.Push(message.release());
-  NS_ENSURE_TRUE(mMessagesToDispatch.GetSize() == sizeBefore + 1,
-                 NS_ERROR_OUT_OF_MEMORY);
-
 
   if (!mGoingToDispatchAllMessages) {
     nsCOMPtr<nsIRunnable> event =
       NewRunnableMethod("dom::EventSourceImpl::DispatchAllMessageEvents",
                         this,
                         &EventSourceImpl::DispatchAllMessageEvents);
     NS_ENSURE_STATE(event);
 
--- a/dom/base/ProcessSelector.js
+++ b/dom/base/ProcessSelector.js
@@ -7,17 +7,17 @@ ChromeUtils.import('resource://gre/modul
 
 // Fills up aProcesses until max and then selects randomly from the available
 // ones.
 function RandomSelector() {
 }
 
 RandomSelector.prototype = {
   classID:          Components.ID("{c616fcfd-9737-41f1-aa74-cee72a38f91b}"),
-  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIContentProcessProvider]),
+  QueryInterface:   ChromeUtils.generateQI([Ci.nsIContentProcessProvider]),
 
   provideProcess(aType, aOpener, aProcesses, aCount, aMaxCount) {
     if (aCount < aMaxCount) {
       return Ci.nsIContentProcessProvider.NEW_PROCESS;
     }
 
     let startIdx = Math.floor(Math.random() * aMaxCount);
     let curIdx = startIdx;
@@ -36,17 +36,17 @@ RandomSelector.prototype = {
 
 // Fills up aProcesses until max and then selects one from the available
 // ones that host the least number of tabs.
 function MinTabSelector() {
 }
 
 MinTabSelector.prototype = {
   classID:          Components.ID("{2dc08eaf-6eef-4394-b1df-a3a927c1290b}"),
-  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIContentProcessProvider]),
+  QueryInterface:   ChromeUtils.generateQI([Ci.nsIContentProcessProvider]),
 
   provideProcess(aType, aOpener, aProcesses, aCount, aMaxCount) {
     if (aCount < aMaxCount) {
       return Ci.nsIContentProcessProvider.NEW_PROCESS;
     }
 
     let min = Number.MAX_VALUE;
     let candidate = Ci.nsIContentProcessProvider.NEW_PROCESS;
--- a/dom/base/SlowScriptDebug.js
+++ b/dom/base/SlowScriptDebug.js
@@ -7,17 +7,17 @@
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function SlowScriptDebug() { }
 
 SlowScriptDebug.prototype = {
   classID: Components.ID("{e740ddb4-18b4-4aac-8ae1-9b0f4320769d}"),
   classDescription: "Slow script debug handler",
   contractID: "@mozilla.org/dom/slow-script-debug;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISlowScriptDebug]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsISlowScriptDebug]),
 
   get activationHandler()   { return this._activationHandler; },
   set activationHandler(cb) { return this._activationHandler = cb; },
 
   get remoteActivationHandler()   { return this._remoteActivationHandler; },
   set remoteActivationHandler(cb) { return this._remoteActivationHandler = cb; },
 };
 
--- a/dom/base/contentAreaDropListener.js
+++ b/dom/base/contentAreaDropListener.js
@@ -13,17 +13,17 @@ ChromeUtils.import("resource://gre/modul
 // access the uri. This prevents, for example, a source document from tricking
 // the user into dragging a chrome url.
 
 function ContentAreaDropListener() { };
 
 ContentAreaDropListener.prototype =
 {
   classID:          Components.ID("{1f34bc80-1bc7-11d6-a384-d705dd0746fc}"),
-  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIDroppedLinkHandler, Ci.nsISupports]),
+  QueryInterface:   ChromeUtils.generateQI([Ci.nsIDroppedLinkHandler]),
 
   _addLink : function(links, url, name, type)
    {
     links.push({ url, name, type });
   },
 
   _addLinksFromItem: function(links, dt, i)
   {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -5539,18 +5539,18 @@ nsContentUtils::TriggerLink(nsIContent *
          !aContent->IsSVGElement(nsGkAtoms::a)) ||
         !aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::download, fileName) ||
         NS_FAILED(aContent->NodePrincipal()->CheckMayLoad(aLinkURI, false, true))) {
       fileName.SetIsVoid(true); // No actionable download attribute was found.
     }
 
     handler->OnLinkClick(aContent, aLinkURI,
                          fileName.IsVoid() ? aTargetSpec.get() : EmptyString().get(),
-                         fileName, nullptr, -1, nullptr, aIsTrusted,
-                         aContent->NodePrincipal());
+                         fileName, nullptr, -1, nullptr, EventStateManager::IsHandlingUserInput(),
+                         aIsTrusted, aContent->NodePrincipal());
   }
 }
 
 /* static */
 void
 nsContentUtils::GetLinkLocation(Element* aElement, nsString& aLocationString)
 {
   nsCOMPtr<nsIURI> hrefURI = aElement->GetHrefURI();
@@ -6688,19 +6688,17 @@ nsContentUtils::IsFocusedContent(const n
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 
   return fm && fm->GetFocusedElement() == aContent;
 }
 
 bool
 nsContentUtils::IsSubDocumentTabbable(nsIContent* aContent)
 {
-  //XXXsmaug Shadow DOM spec issue!
-  //         We may need to change this to GetComposedDoc().
-  nsIDocument* doc = aContent->GetUncomposedDoc();
+  nsIDocument* doc = aContent->GetComposedDoc();
   if (!doc) {
     return false;
   }
 
   // If the subdocument lives in another process, the frame is
   // tabbable.
   if (EventStateManager::IsRemoteTarget(aContent)) {
     return true;
@@ -9992,43 +9990,43 @@ nsContentUtils::NewXULOrHTMLElement(Elem
     // Step 6.1.
     if (synchronousCustomElements) {
       DoCustomElementCreate(aResult, nodeInfo->GetDocument(), nodeInfo,
                             definition->mConstructor, rv);
       if (rv.MaybeSetPendingException(cx)) {
         if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
           NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser));
         } else {
-          NS_IF_ADDREF(*aResult = new nsXULElement(nodeInfo.forget()));
+          NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()));
         }
       }
       return NS_OK;
     }
 
     // Step 6.2.
     if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
       NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
     } else {
-      NS_IF_ADDREF(*aResult = new nsXULElement(nodeInfo.forget()));
+      NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()));
     }
     (*aResult)->SetCustomElementData(new CustomElementData(definition->mType));
     nsContentUtils::EnqueueUpgradeReaction(*aResult, definition);
     return NS_OK;
   }
 
   if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
     // Per the Custom Element specification, unknown tags that are valid custom
     // element names should be HTMLElement instead of HTMLUnknownElement.
     if (isCustomElementName) {
       NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
     } else {
       *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
     }
   } else {
-    NS_IF_ADDREF(*aResult = new nsXULElement(nodeInfo.forget()));
+    NS_IF_ADDREF(*aResult = nsXULElement::Construct(nodeInfo.forget()));
   }
 
   if (!*aResult) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (customElementEnabled && isCustomElement) {
     (*aResult)->SetCustomElementData(new CustomElementData(typeAtom));
--- a/dom/base/nsDOMNavigationTiming.cpp
+++ b/dom/base/nsDOMNavigationTiming.cpp
@@ -292,16 +292,43 @@ nsDOMNavigationTiming::NotifyNonBlankPai
 
     Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_NON_BLANK_PAINT_MS,
                                    mNavigationStart,
                                    mNonBlankPaint);
   }
 }
 
 void
+nsDOMNavigationTiming::NotifyDOMContentFlushedForRootContentDocument()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mNavigationStart.IsNull());
+
+  if (!mDOMContentFlushed.IsNull()) {
+    return;
+  }
+
+  mDOMContentFlushed = TimeStamp::Now();
+
+#ifdef MOZ_GECKO_PROFILER
+  if (profiler_is_active()) {
+    TimeDuration elapsed = mDOMContentFlushed - mNavigationStart;
+    nsAutoCString spec;
+    if (mLoadedURI) {
+      mLoadedURI->GetSpec(spec);
+    }
+    nsPrintfCString marker("DOMContentFlushed after %dms for URL %s, %s",
+                           int(elapsed.ToMilliseconds()), spec.get(),
+                           mDocShellHasBeenActiveSinceNavigationStart ? "foreground tab" : "this tab was inactive some of the time between navigation start and DOMContentFlushed");
+    profiler_add_marker(marker.get());
+  }
+#endif
+}
+
+void
 nsDOMNavigationTiming::NotifyDocShellStateChanged(DocShellState aDocShellState)
 {
   mDocShellHasBeenActiveSinceNavigationStart &=
     (aDocShellState == DocShellState::eActive);
 }
 
 mozilla::TimeStamp
 nsDOMNavigationTiming::GetUnloadEventStartTimeStamp() const
--- a/dom/base/nsDOMNavigationTiming.h
+++ b/dom/base/nsDOMNavigationTiming.h
@@ -91,16 +91,20 @@ public:
   DOMTimeMilliSec GetLoadEventEnd() const
   {
     return TimeStampToDOM(mLoadEventEnd);
   }
   DOMTimeMilliSec GetTimeToNonBlankPaint() const
   {
     return TimeStampToDOM(mNonBlankPaint);
   }
+  DOMTimeMilliSec GetTimeToDOMContentFlushed() const
+  {
+    return TimeStampToDOM(mDOMContentFlushed);
+  }
 
   DOMHighResTimeStamp GetUnloadEventStartHighRes()
   {
     mozilla::TimeStamp stamp = GetUnloadEventStartTimeStamp();
     if (stamp.IsNull()) {
       return 0;
     }
     return TimeStampToDOMHighRes(stamp);
@@ -156,16 +160,17 @@ public:
   void SetDOMLoadingTimeStamp(nsIURI* aURI, mozilla::TimeStamp aValue);
   void NotifyDOMLoading(nsIURI* aURI);
   void NotifyDOMInteractive(nsIURI* aURI);
   void NotifyDOMComplete(nsIURI* aURI);
   void NotifyDOMContentLoadedStart(nsIURI* aURI);
   void NotifyDOMContentLoadedEnd(nsIURI* aURI);
 
   void NotifyNonBlankPaintForRootContentDocument();
+  void NotifyDOMContentFlushedForRootContentDocument();
   void NotifyDocShellStateChanged(DocShellState aDocShellState);
 
   DOMTimeMilliSec TimeStampToDOM(mozilla::TimeStamp aStamp) const;
 
   inline DOMHighResTimeStamp TimeStampToDOMHighRes(mozilla::TimeStamp aStamp) const
   {
     if (aStamp.IsNull()) {
       return 0;
@@ -189,16 +194,17 @@ private:
 
   nsCOMPtr<nsIURI> mUnloadedURI;
   nsCOMPtr<nsIURI> mLoadedURI;
 
   Type mNavigationType;
   DOMHighResTimeStamp mNavigationStartHighRes;
   mozilla::TimeStamp mNavigationStart;
   mozilla::TimeStamp mNonBlankPaint;
+  mozilla::TimeStamp mDOMContentFlushed;
 
   mozilla::TimeStamp mBeforeUnloadStart;
   mozilla::TimeStamp mUnloadStart;
   mozilla::TimeStamp mUnloadEnd;
   mozilla::TimeStamp mLoadEventStart;
   mozilla::TimeStamp mLoadEventEnd;
 
   mozilla::TimeStamp mDOMLoading;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -251,17 +251,16 @@
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/TabGroup.h"
 #ifdef MOZ_XUL
 #include "mozilla/dom/ListBoxObject.h"
 #include "mozilla/dom/MenuBoxObject.h"
-#include "mozilla/dom/PopupBoxObject.h"
 #include "mozilla/dom/ScrollBoxObject.h"
 #include "mozilla/dom/TreeBoxObject.h"
 #endif
 #include "nsIPresShellInlines.h"
 
 #include "mozilla/DocLoadingTimelineMarker.h"
 
 #include "nsISpeculativeConnect.h"
@@ -5460,16 +5459,20 @@ nsIDocument::UnblockDOMContentLoaded()
   MOZ_ASSERT(mBlockDOMContentLoaded);
   if (--mBlockDOMContentLoaded != 0 || mDidFireDOMContentLoaded) {
     return;
   }
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p UnblockDOMContentLoaded", this));
 
   mDidFireDOMContentLoaded = true;
+  if (nsIPresShell* shell = GetShell()) {
+    shell->GetRefreshDriver()->NotifyDOMContentLoaded();
+  }
+
 
   MOZ_ASSERT(mReadyState == READYSTATE_INTERACTIVE);
   if (!mSynchronousDOMContentLoaded) {
     MOZ_RELEASE_ASSERT(NS_IsMainThread());
     nsCOMPtr<nsIRunnable> ev =
       NewRunnableMethod("nsIDocument::DispatchContentLoadedEvents",
                         this,
                         &nsIDocument::DispatchContentLoadedEvents);
@@ -6571,21 +6574,16 @@ nsIDocument::GetBoxObjectFor(Element* aE
   }
 
   int32_t namespaceID;
   RefPtr<nsAtom> tag = BindingManager()->ResolveTag(aElement, &namespaceID);
 #ifdef MOZ_XUL
   if (namespaceID == kNameSpaceID_XUL) {
     if (tag == nsGkAtoms::menu) {
       boxObject = new MenuBoxObject();
-    } else if (tag == nsGkAtoms::popup ||
-               tag == nsGkAtoms::menupopup ||
-               tag == nsGkAtoms::panel ||
-               tag == nsGkAtoms::tooltip) {
-      boxObject = new PopupBoxObject();
     } else if (tag == nsGkAtoms::tree) {
       boxObject = new TreeBoxObject();
     } else if (tag == nsGkAtoms::listbox) {
       boxObject = new ListBoxObject();
     } else if (tag == nsGkAtoms::scrollbox) {
       boxObject = new ScrollBoxObject();
     } else {
       boxObject = new BoxObject();
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -3234,19 +3234,21 @@ nsFocusManager::HostOrSlotTabIndexValue(
   }
 
   return -1;
 }
 
 nsIContent*
 nsFocusManager::GetNextTabbableContentInScope(nsIContent* aOwner,
                                               nsIContent* aStartContent,
+                                              nsIContent* aOriginalStartContent,
                                               bool aForward,
                                               int32_t aCurrentTabIndex,
                                               bool aIgnoreTabIndex,
+                                              bool aForDocumentNavigation,
                                               bool aSkipOwner)
 {
   // Return shadow host at first for forward navigation if its tabindex
   // is non-negative
   bool skipOwner = aSkipOwner || !aOwner->GetShadowRoot();
   if (!skipOwner && (aForward && aOwner == aStartContent)) {
     int32_t tabIndex = 0;
     aOwner->IsFocusable(&tabIndex);
@@ -3356,24 +3358,43 @@ nsFocusManager::GetNextTabbableContentIn
             }
           }
         }
 
         continue;
       }
 
       if (!IsHostOrSlot(iterContent)) {
+        nsCOMPtr<nsIContent> elementInFrame;
+        bool checkSubDocument = true;
+        if (aForDocumentNavigation &&
+            TryDocumentNavigation(iterContent, &checkSubDocument,
+                                  getter_AddRefs(elementInFrame))) {
+          return elementInFrame;
+        }
+        if (!checkSubDocument) {
+          continue;
+        }