Merge mozilla-central to autoland. a=merge on a CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Sat, 28 Apr 2018 20:41:18 +0300
changeset 416171 f35994b437e3b0d9e61f74b34de2cf4cb80ab458
parent 416170 6cf6124bbd25db02658997b21bf9cfdc470fdbca (current diff)
parent 416169 08f68e2c892cadc4035ecbfbf3529f32d40f1fd9 (diff)
child 416172 cd79c351e29628d110cbd01af5fd54edafbedbec
push id33918
push usernerli@mozilla.com
push dateSun, 29 Apr 2018 09:47:13 +0000
treeherdermozilla-central@afbec7f03bd8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge on a CLOSED TREE
dom/webidl/PopupBoxObject.webidl
layout/xul/PopupBoxObject.cpp
layout/xul/PopupBoxObject.h
layout/xul/crashtests/434458-1.xul
--- 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/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/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"].
--- 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-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_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/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",
--- 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/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/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);
@@ -1970,20 +1968,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/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/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/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/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/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/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");
--- 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/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/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;
+        }
+
+        if (TryToMoveFocusToSubDocument(iterContent, aOriginalStartContent,
+                                        aForward, aForDocumentNavigation,
+                                        getter_AddRefs(elementInFrame))) {
+          return elementInFrame;
+        }
+
         // Found content to focus
         return iterContent;
       }
 
       // Search in scope owned by iterContent
       nsIContent* contentToFocus =
-        GetNextTabbableContentInScope(iterContent, iterContent, aForward,
+        GetNextTabbableContentInScope(iterContent, iterContent,
+                                      aOriginalStartContent, aForward,
                                       aForward ? 1 : 0, aIgnoreTabIndex,
+                                      aForDocumentNavigation,
                                       false /* aSkipOwner */);
       if (contentToFocus) {
         return contentToFocus;
       }
     };
 
     // If already at lowest priority tab (0), end search completely.
     // A bit counterintuitive but true, tabindex order goes 1, 2, ... 32767, 0
@@ -3397,30 +3418,33 @@ nsFocusManager::GetNextTabbableContentIn
   }
 
   return nullptr;
 }
 
 nsIContent*
 nsFocusManager::GetNextTabbableContentInAncestorScopes(
   nsIContent** aStartContent,
+  nsIContent* aOriginalStartContent,
   bool aForward,
   int32_t* aCurrentTabIndex,
-  bool aIgnoreTabIndex)
+  bool aIgnoreTabIndex,
+  bool aForDocumentNavigation)
 {
   nsIContent* startContent = *aStartContent;
   while (1) {
     nsIContent* owner = FindOwner(startContent);
     MOZ_ASSERT(owner, "focus navigation scope owner not in document");
 
     int32_t tabIndex = 0;
     startContent->IsFocusable(&tabIndex);
     nsIContent* contentToFocus =
-      GetNextTabbableContentInScope(owner, startContent, aForward,
-                                    tabIndex, aIgnoreTabIndex,
+      GetNextTabbableContentInScope(owner, startContent, aOriginalStartContent,
+                                    aForward, tabIndex, aIgnoreTabIndex,
+                                    aForDocumentNavigation,
                                     false /* aSkipOwner */);
     if (contentToFocus) {
       return contentToFocus;
     }
 
     // If not found in shadow DOM, search from the shadow host in light DOM
     if (!owner->IsInShadowTree()) {
       MOZ_ASSERT(owner->GetShadowRoot());
@@ -3456,33 +3480,38 @@ nsFocusManager::GetNextTabbableContent(n
   LOGCONTENTNAVIGATION("GetNextTabbable: %s", aStartContent);
   LOGFOCUSNAVIGATION(("  tabindex: %d", aCurrentTabIndex));
 
   if (nsDocument::IsShadowDOMEnabled(aRootContent)) {
     // If aStartContent is a shadow host or slot in forward navigation,
     // search in scope owned by aStartContent
     if (aForward && IsHostOrSlot(aStartContent)) {
       nsIContent* contentToFocus =
-        GetNextTabbableContentInScope(aStartContent, aStartContent, aForward,
+        GetNextTabbableContentInScope(aStartContent, aStartContent,
+                                      aOriginalStartContent, aForward,
                                       aForward ? 1 : 0, aIgnoreTabIndex,
+                                      aForDocumentNavigation,
                                       true /* aSkipOwner */);
       if (contentToFocus) {
         NS_ADDREF(*aResultContent = contentToFocus);
         return NS_OK;
       }
     }
 
     // If aStartContent is not in scope owned by aRootContent
     // (e.g., aStartContent is already in shadow DOM),
     // search from scope including aStartContent
     if (aRootContent != FindOwner(aStartContent)) {
       nsIContent* contentToFocus =
-        GetNextTabbableContentInAncestorScopes(&aStartContent, aForward,
+        GetNextTabbableContentInAncestorScopes(&aStartContent,
+                                               aOriginalStartContent,
+                                               aForward,
                                                &aCurrentTabIndex,
-                                               aIgnoreTabIndex);
+                                               aIgnoreTabIndex,
+                                               aForDocumentNavigation);
       if (contentToFocus) {
         NS_ADDREF(*aResultContent = contentToFocus);
         return NS_OK;
       }
     }
 
     // If we reach here, it means no next tabbable content in shadow DOM.
     // We need to continue searching in light DOM, starting at the shadow host
@@ -3604,18 +3633,20 @@ nsFocusManager::GetNextTabbableContent(n
       // and later in "For each element ELEMENT in NAVIGATION-ORDER: "
       // hosts and slots are handled before other elements.
       if (currentContent && nsDocument::IsShadowDOMEnabled(currentContent) &&
           IsHostOrSlot(currentContent)) {
         int32_t tabIndex = HostOrSlotTabIndexValue(currentContent);
         if (tabIndex >= 0 &&
             (aIgnoreTabIndex || aCurrentTabIndex == tabIndex)) {
           nsIContent* contentToFocus =
-            GetNextTabbableContentInScope(currentContent, currentContent, aForward,
+            GetNextTabbableContentInScope(currentContent, currentContent,
+                                          aOriginalStartContent, aForward,
                                           aForward ? 1 : 0, aIgnoreTabIndex,
+                                          aForDocumentNavigation,
                                           true /* aSkipOwner */);
           if (contentToFocus) {
             NS_ADDREF(*aResultContent = contentToFocus);
             return NS_OK;
           }
         }
       }
 
@@ -3662,64 +3693,31 @@ nsFocusManager::GetNextTabbableContent(n
           TabParent* remote = TabParent::GetFrom(currentContent);
           if (remote) {
             remote->NavigateByKey(aForward, aForDocumentNavigation);
             return NS_SUCCESS_DOM_NO_OPERATION;
           }
 
           // Next, for document navigation, check if this a non-remote child document.
           bool checkSubDocument = true;
-          if (aForDocumentNavigation) {
-            Element* docRoot = GetRootForChildDocument(currentContent);
-            if (docRoot) {
-              // If GetRootForChildDocument returned something then call
-              // FocusFirst to find the root or first element to focus within
-              // the child document. If this is a frameset though, skip this and
-              // fall through to the checkSubDocument block below to iterate into
-              // the frameset's frames and locate the first focusable frame.
-              if (!docRoot->IsHTMLElement(nsGkAtoms::frameset)) {
-                return FocusFirst(docRoot, aResultContent);
-              }
-            } else {
-              // Set checkSubDocument to false, as this was neither a frame
-              // type element or a child document that was focusable.
-              checkSubDocument = false;
-            }
+          if (aForDocumentNavigation &&
+              TryDocumentNavigation(currentContent, &checkSubDocument,
+                                    aResultContent)) {
+            return NS_OK;
           }
 
           if (checkSubDocument) {
             // found a node with a matching tab index. Check if it is a child
             // frame. If so, navigate into the child frame instead.
-            nsIDocument* doc = currentContent->GetComposedDoc();
-            NS_ASSERTION(doc, "content not in document");
-            nsIDocument* subdoc = doc->GetSubDocumentFor(currentContent);
-            if (subdoc && !subdoc->EventHandlingSuppressed()) {
-              if (aForward) {
-                // when tabbing forward into a frame, return the root
-                // frame so that the canvas becomes focused.
-                nsCOMPtr<nsPIDOMWindowOuter> subframe = subdoc->GetWindow();
-                if (subframe) {
-                  *aResultContent = GetRootForFocus(subframe, subdoc, false, true);
-                  if (*aResultContent) {
-                    NS_ADDREF(*aResultContent);
-                    return NS_OK;
-                  }
-                }
-              }
-              Element* rootElement = subdoc->GetRootElement();
-              nsIPresShell* subShell = subdoc->GetShell();
-              if (rootElement && subShell) {
-                rv = GetNextTabbableContent(subShell, rootElement,
-                                            aOriginalStartContent, rootElement,
-                                            aForward, (aForward ? 1 : 0),
-                                            false, aForDocumentNavigation, aResultContent);
-                NS_ENSURE_SUCCESS(rv, rv);
-                if (*aResultContent)
-                  return NS_OK;
-              }
+            if (TryToMoveFocusToSubDocument(currentContent,
+                                            aOriginalStartContent,
+                                            aForward, aForDocumentNavigation,
+                                            aResultContent)) {
+              MOZ_ASSERT(*aResultContent);
+              return NS_OK;
             }
             // otherwise, use this as the next content node to tab to, unless
             // this was the element we started on. This would happen for
             // instance on an element with child frames, where frame navigation
             // could return the original element again. In that case, just skip
             // it. Also, if the next content node is the root content, then
             // return it. This latter case would happen only if someone made a
             // popup focusable.
@@ -3733,18 +3731,20 @@ nsFocusManager::GetNextTabbableContent(n
 
               if (nsDocument::IsShadowDOMEnabled(aRootContent)) {
                 // If currentContent is a shadow host in backward
                 // navigation, search in scope owned by currentContent
                 if (!aForward && currentContent->GetShadowRoot()) {
                   nsIContent* contentToFocus =
                     GetNextTabbableContentInScope(currentContent,
                                                   currentContent,
+                                                  aOriginalStartContent,
                                                   aForward, aForward ? 1 : 0,
                                                   aIgnoreTabIndex,
+                                                  aForDocumentNavigation,
                                                   true /* aSkipOwner */);
                   if (contentToFocus) {
                     NS_ADDREF(*aResultContent = contentToFocus);
                     return NS_OK;
                   }
                 }
               }
 
@@ -3798,16 +3798,83 @@ nsFocusManager::GetNextTabbableContent(n
     // continue looking for next highest priority tabindex
     aCurrentTabIndex = GetNextTabIndex(aRootContent, aCurrentTabIndex, aForward);
     startContent = iterStartContent = aRootContent;
   }
 
   return NS_OK;
 }
 
+bool
+nsFocusManager::TryDocumentNavigation(nsIContent* aCurrentContent,
+                                      bool* aCheckSubDocument,
+                                      nsIContent** aResultContent)
+{
+  *aCheckSubDocument = true;
+  Element* docRoot = GetRootForChildDocument(aCurrentContent);
+  if (docRoot) {
+    // If GetRootForChildDocument returned something then call
+    // FocusFirst to find the root or first element to focus within
+    // the child document. If this is a frameset though, skip this and
+    // fall through to normal tab navigation to iterate into
+    // the frameset's frames and locate the first focusable frame.
+    if (!docRoot->IsHTMLElement(nsGkAtoms::frameset)) {
+      *aCheckSubDocument = false;
+      Unused << FocusFirst(docRoot, aResultContent);
+      return *aResultContent != nullptr;
+    }
+  } else {
+    // Set aCheckSubDocument to false, as this was neither a frame
+    // type element or a child document that was focusable.
+    *aCheckSubDocument = false;
+  }
+
+  return false;
+}
+
+bool
+nsFocusManager::TryToMoveFocusToSubDocument(nsIContent* aCurrentContent,
+                                            nsIContent* aOriginalStartContent,
+                                            bool aForward,
+                                            bool aForDocumentNavigation,
+                                            nsIContent** aResultContent)
+{
+  nsIDocument* doc = aCurrentContent->GetComposedDoc();
+  NS_ASSERTION(doc, "content not in document");
+  nsIDocument* subdoc = doc->GetSubDocumentFor(aCurrentContent);
+  if (subdoc && !subdoc->EventHandlingSuppressed()) {
+    if (aForward) {
+      // when tabbing forward into a frame, return the root
+      // frame so that the canvas becomes focused.
+      nsCOMPtr<nsPIDOMWindowOuter> subframe = subdoc->GetWindow();
+      if (subframe) {
+        *aResultContent = GetRootForFocus(subframe, subdoc, false, true);
+        if (*aResultContent) {
+          NS_ADDREF(*aResultContent);
+          return true;
+        }
+      }
+    }
+    Element* rootElement = subdoc->GetRootElement();
+    nsIPresShell* subShell = subdoc->GetShell();
+    if (rootElement && subShell) {
+      nsresult rv = GetNextTabbableContent(subShell, rootElement,
+                                           aOriginalStartContent, rootElement,
+                                           aForward, (aForward ? 1 : 0),
+                                           false, aForDocumentNavigation,
+                                           aResultContent);
+      NS_ENSURE_SUCCESS(rv, false);
+      if (*aResultContent) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 nsIContent*
 nsFocusManager::GetNextTabbableMapArea(bool aForward,
                                        int32_t aCurrentTabIndex,
                                        Element* aImageContent,
                                        nsIContent* aStartContent)
 {
   nsAutoString useMap;
   aImageContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usemap, useMap);
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -457,67 +457,83 @@ protected:
   /**
    * Retrieve the next tabbable element in scope owned by aOwner, using
    * focusability and tabindex to determine the tab order.
    *
    * aOwner is the owner of scope to search in.
    *
    * aStartContent is the starting point for this call of this method.
    *
+   * aOriginalStartContent is the initial starting point for sequential
+   * navigation.
+   *
    * aForward should be true for forward navigation or false for backward
    * navigation.
    *
    * aCurrentTabIndex is the current tabindex.
    *
    * aIgnoreTabIndex to ignore the current tabindex and find the element
    * irrespective or the tab index.
    *
+   * aForDocumentNavigation informs whether we're navigating only through
+   * documents.
+   *
    * aSkipOwner to skip owner while searching. The flag is set when caller is
    * |GetNextTabbableContent| in order to let caller handle owner.
    *
    * NOTE:
    *   Consider the method searches downwards in flattened subtree
    *   rooted at aOwner.
    */
   nsIContent* GetNextTabbableContentInScope(nsIContent* aOwner,
                                             nsIContent* aStartContent,
+                                            nsIContent* aOriginalStartContent,
                                             bool aForward,
                                             int32_t aCurrentTabIndex,
                                             bool aIgnoreTabIndex,
+                                            bool aForDocumentNavigation,
                                             bool aSkipOwner);
 
   /**
    * Retrieve the next tabbable element in scope including aStartContent
    * and the scope's ancestor scopes, using focusability and tabindex to
    * determine the tab order.
    *
    * aStartContent an in/out paremeter. It as input is the starting point
    * for this call of this method; as output it is the shadow host in
    * light DOM if the next tabbable element is not found in shadow DOM,
    * in order to continue searching in light DOM.
    *
+   * aOriginalStartContent is the initial starting point for sequential
+   * navigation.
+   *
    * aForward should be true for forward navigation or false for backward
    * navigation.
    *
    * aCurrentTabIndex returns tab index of shadow host in light DOM if the
    * next tabbable element is not found in shadow DOM, in order to continue
    * searching in light DOM.
    *
    * aIgnoreTabIndex to ignore the current tabindex and find the element
    * irrespective or the tab index.
    *
+   * aForDocumentNavigation informs whether we're navigating only through
+   * documents.
+   *
    * NOTE:
    *   Consider the method searches upwards in all shadow host- or slot-rooted
    *   flattened subtrees that contains aStartContent as non-root, except
    *   the flattened subtree rooted at shadow host in light DOM.
    */
   nsIContent* GetNextTabbableContentInAncestorScopes(nsIContent** aStartContent,
+                                                     nsIContent* aOriginalStartContent,
                                                      bool aForward,
                                                      int32_t* aCurrentTabIndex,
-                                                     bool aIgnoreTabIndex);
+                                                     bool aIgnoreTabIndex,
+                                                     bool aForDocumentNavigation);
 
   /**
    * Retrieve the next tabbable element within a document, using focusability
    * and tabindex to determine the tab order. The element is returned in
    * aResultContent.
    *
    * aRootContent is the root node -- nodes above this will not be examined.
    * Typically this will be the root node of a document, but could also be
@@ -629,16 +645,26 @@ private:
   // wrong..
   static void NotifyFocusStateChange(nsIContent* aContent,
                                      nsIContent* aContentToFocus,
                                      bool aWindowShouldShowFocusRing,
                                      bool aGettingFocus);
 
   void SetFocusedWindowInternal(nsPIDOMWindowOuter* aWindow);
 
+  bool TryDocumentNavigation(nsIContent* aCurrentContent,
+                             bool* aCheckSubDocument,
+                             nsIContent** aResultContent);
+
+  bool TryToMoveFocusToSubDocument(nsIContent* aCurrentContent,
+                                   nsIContent* aOriginalStartContent,
+                                   bool aForward,
+                                   bool aForDocumentNavigation,
+                                   nsIContent** aResultContent);
+
   // the currently active and front-most top-most window
   nsCOMPtr<nsPIDOMWindowOuter> mActiveWindow;
 
   // the child or top-level window that is currently focused. This window will
   // either be the same window as mActiveWindow or a descendant of it.
   // Except during shutdown use SetFocusedWindowInternal to set mFocusedWindow!
   nsCOMPtr<nsPIDOMWindowOuter> mFocusedWindow;
 
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -5199,30 +5199,21 @@ nsGlobalWindowInner::FireOfflineStatusEv
   mWasOffline = !mWasOffline;
 
   nsAutoString name;
   if (mWasOffline) {
     name.AssignLiteral("offline");
   } else {
     name.AssignLiteral("online");
   }
-  // The event is fired at the body element, or if there is no body element,
-  // at the document.
-  nsCOMPtr<EventTarget> eventTarget = mDoc.get();
-  if (mDoc->IsHTMLOrXHTML()) {
-    if (Element* body = mDoc->GetBody()) {
-      eventTarget = body;
-    }
-  } else {
-    Element* documentElement = mDoc->GetDocumentElement();
-    if (documentElement) {
-      eventTarget = documentElement;
-    }
-  }
-  nsContentUtils::DispatchTrustedEvent(mDoc, eventTarget, name, true, false);
+  nsContentUtils::DispatchTrustedEvent(mDoc,
+                                       static_cast<EventTarget*>(this),
+                                       name,
+                                       false,
+                                       false);
 }
 
 class NotifyIdleObserverRunnable : public Runnable
 {
 public:
   NotifyIdleObserverRunnable(nsIIdleObserver* aIdleObserver,
                              uint32_t aTimeInS,
                              bool aCallOnidle,
--- a/dom/base/test/browser_bug1303838.js
+++ b/dom/base/test/browser_bug1303838.js
@@ -161,14 +161,14 @@ function waitForLocationChange(browser, 
     locationChangeListener = {
       onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
         info("LocationChange: " + aLocation.spec);
         if (++seen == locationChangeNum) {
           browser.removeProgressListener(this);
           resolve();
         }
       },
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                             Ci.nsISupportsWeakReference])
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                              Ci.nsISupportsWeakReference])
     };
     browser.addProgressListener(locationChangeListener);
   });
 }
--- a/dom/base/test/browser_promiseDocumentFlushed.js
+++ b/dom/base/test/browser_promiseDocumentFlushed.js
@@ -116,18 +116,18 @@ add_task(async function test_can_get_res
   assertFlushesRequired();
 
   let rect = await window.promiseDocumentFlushed(() => {
     let observer = {
       reflow() {
         Assert.ok(false, "A reflow should not have occurred.");
       },
       reflowInterruptible() {},
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
-                                             Ci.nsISupportsWeakReference])
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIReflowObserver,
+                                              Ci.nsISupportsWeakReference])
     };
 
     let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIWebNavigation)
                          .QueryInterface(Ci.nsIDocShell);
     docShell.addWeakReflowObserver(observer);
 
     let toolboxRect = gNavToolbox.getBoundingClientRect();
--- a/dom/base/test/chrome/file_bug549682.xul
+++ b/dom/base/test/chrome/file_bug549682.xul
@@ -87,33 +87,33 @@ https://bugzilla.mozilla.org/show_bug.cg
   function localL(m) {
     is(m.name, "lasync", "Wrong message!");
     is(m.json.data, 2345, "Wrong data!");
     didRunLocal = true;
   }
 
   var weakMessageReceived = false;
   var weakListener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference]),
 
     receiveMessage: function(msg) {
       if (weakMessageReceived) {
         ok(false, 'Weak listener fired twice.');
         return;
       }
 
       ok(true, 'Weak listener fired once.');
       weakMessageReceived = true;
       document.getElementById('ifr').messageManager
               .removeWeakMessageListener('weak', weakListener);
     }
   };
 
   var weakListener2 = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference]),
 
     receiveMessage: function(msg) {
       ok(false, 'Should not have received a message.');
     }
   };
 
   function weakDoneListener() {
     ok(weakMessageReceived, 'Got "weak" message.');
--- a/dom/base/test/chrome/test_bug682305.html
+++ b/dom/base/test/chrome/test_bug682305.html
@@ -88,17 +88,17 @@ CustomChannel.prototype = {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
   suspend: function() {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
   resume: function() {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
 };
 
 
 function CustomProtocol() {}
 CustomProtocol.prototype = {
   get scheme() {
     return PROTOCOL_SCHEME;
   },
@@ -120,19 +120,17 @@ CustomProtocol.prototype = {
              .finalize();
   },
   newChannel2: function newChannel2(URI, loadInfo) {
     return new CustomChannel(URI, loadInfo);
   },
   newChannel: function newChannel(URI) {
     return newChannel2(URI);
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsIProtocolHandler])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIProtocolHandler])
 };
 
 var gFactory = {
   register: function() {
     var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 
     var classID = Components.ID("{ed064287-1e76-49ba-a28d-dc74394a8334}");
     var description = PROTOCOL_SCHEME + ": protocol";
--- a/dom/base/test/chrome/test_bug800386.xul
+++ b/dom/base/test/chrome/test_bug800386.xul
@@ -41,18 +41,17 @@ https://bugzilla.mozilla.org/show_bug.cg
           return xhr2.getInterface(aIID);
         } catch (e) {
           forwardFailed = true;
         }
       }
       throw Cr.NS_ERROR_NO_INTERFACE;
     },
 
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                           Ci.nsIInterfaceRequestor])
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIInterfaceRequestor])
   };
 
   // HTTP URI so that we get progress callbacks
   xhr.open("GET", "http://mochi.test:8888/", false);
   xhr.channel.notificationCallbacks = requestor;
   xhr.onreadystatechange = function() {
     if (xhr.readyState == 4) {
       ok(triedForwarding,
--- a/dom/base/test/file_bug1453693.html
+++ b/dom/base/test/file_bug1453693.html
@@ -32,16 +32,21 @@
         sr.appendChild(shadowInput);
 
         var shadowDate = document.createElement("input");
         shadowDate.type = "date";
         shadowDate.onfocus = focusLogger;
         shadowDate.tabIndex = 1;
         sr.appendChild(shadowDate);
 
+        var shadowIframe = document.createElement("iframe");
+        shadowIframe.tabIndex = 1;
+        sr.appendChild(shadowIframe);
+        shadowIframe.contentDocument.body.innerHTML = "<input>";
+
         var input = document.createElement("input");
         input.onfocus = focusLogger;
         input.tabIndex = 1;
         document.body.appendChild(input);
 
         var input2 = document.createElement("input");
         input2.onfocus = focusLogger;
         document.body.appendChild(input2);
@@ -56,24 +61,40 @@
         opener.is(lastFocusTarget, shadowInput, "Should have focused input element in shadow DOM. (3)");
         synthesizeKey("KEY_Tab");
         opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (3)");
         synthesizeKey("KEY_Tab");
         opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (3)");
         synthesizeKey("KEY_Tab");
         opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (3)");
         synthesizeKey("KEY_Tab");
+        opener.is(shadowIframe.contentDocument.activeElement,
+                  shadowIframe.contentDocument.documentElement,
+                  "Should have focused document element in shadow iframe. (3)");
+        synthesizeKey("KEY_Tab");
+        opener.is(shadowIframe.contentDocument.activeElement,
+                  shadowIframe.contentDocument.body.firstChild,
+                  "Should have focused input element in shadow iframe. (3)");
+        synthesizeKey("KEY_Tab");
         opener.is(lastFocusTarget, shadowAnchor, "Should have focused anchor element in shadow DOM. (3)");
         synthesizeKey("KEY_Tab");
         opener.is(lastFocusTarget, input2, "Should have focused input[2] element. (3)");
 
         // Backwards
         synthesizeKey("KEY_Tab", {shiftKey: true});
         opener.is(lastFocusTarget, shadowAnchor, "Should have focused anchor element in shadow DOM. (4)");
         synthesizeKey("KEY_Tab", {shiftKey: true});
+        opener.is(shadowIframe.contentDocument.activeElement,
+                  shadowIframe.contentDocument.body.firstChild,
+                  "Should have focused input element in shadow iframe. (4)");
+        synthesizeKey("KEY_Tab", {shiftKey: true});
+        opener.is(shadowIframe.contentDocument.activeElement,
+                  shadowIframe.contentDocument.documentElement,
+                  "Should have focused document element in shadow iframe. (4)");
+        synthesizeKey("KEY_Tab", {shiftKey: true});
         opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (4)");
         synthesizeKey("KEY_Tab", {shiftKey: true});
         opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (4)");
         synthesizeKey("KEY_Tab", {shiftKey: true});
         opener.is(lastFocusTarget, shadowDate, "Should have focused date element in shadow DOM. (4)");
         synthesizeKey("KEY_Tab", {shiftKey: true});
         opener.is(lastFocusTarget, shadowInput, "Should have focused input element in shadow DOM. (4)");
         synthesizeKey("KEY_Tab", {shiftKey: true});
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -3870,17 +3870,18 @@ HTMLConstructor(JSContext* aCx, unsigned
     RefPtr<NodeInfo> nodeInfo =
       doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName,
                                           nullptr,
                                           ns,
                                           nsINode::ELEMENT_NODE);
     MOZ_ASSERT(nodeInfo);
 
     if (ns == kNameSpaceID_XUL) {
-      element = new nsXULElement(nodeInfo.forget());
+      element = nsXULElement::Construct(nodeInfo.forget());
+
     } else {
       if (tag == eHTMLTag_userdefined) {
         // Autonomous custom element.
         element = NS_NewHTMLElement(nodeInfo.forget());
       } else {
         // Customized built-in element.
         element = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
       }
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -102,20 +102,16 @@ DOMInterfaces = {
     'nativeType': 'mozilla::dom::AudioContext',
 },
 
 'BatteryManager': {
     'nativeType': 'mozilla::dom::battery::BatteryManager',
     'headerFile': 'BatteryManager.h'
 },
 
-'BoxObject': {
-    'resultNotAddRefed': ['element'],
-},
-
 'Cache': {
     'implicitJSContext': [ 'add', 'addAll', 'match', 'matchAll', 'put',
                            'delete', 'keys' ],
     'nativeType': 'mozilla::dom::cache::Cache',
 },
 
 'CacheStorage': {
     'implicitJSContext': [ 'match' ],
@@ -686,20 +682,16 @@ DOMInterfaces = {
 'PluginArray': {
     'nativeType': 'nsPluginArray',
 },
 
 'PluginTag': {
     'nativeType': 'nsIPluginTag',
 },
 
-'PopupBoxObject': {
-    'resultNotAddRefed': ['triggerNode', 'anchorNode'],
-},
-
 'Position': {
     'headerFile': 'nsGeoPosition.h'
 },
 
 'PositionError': {
     'headerFile': 'nsGeolocation.h'
 },
 
--- a/dom/bindings/test/TestInterfaceJS.js
+++ b/dom/bindings/test/TestInterfaceJS.js
@@ -8,19 +8,17 @@
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 function TestInterfaceJS(anyArg, objectArg) {}
 
 TestInterfaceJS.prototype = {
   classID: Components.ID("{2ac4e026-cf25-47d5-b067-78d553c3cad8}"),
   contractID: "@mozilla.org/dom/test-interface-js;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsIDOMGlobalPropertyInitializer,
-                                         Ci.mozITestInterfaceJS]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer, Ci.mozITestInterfaceJS]),
 
   init: function(win) { this._win = win; },
 
   __init: function (anyArg, objectArg, dictionaryArg) {
     this._anyAttr = undefined;
     this._objectAttr = null;
     this._anyArg = anyArg;
     this._objectArg = objectArg;
--- a/dom/bindings/test/TestInterfaceJSMaplike.js
+++ b/dom/bindings/test/TestInterfaceJSMaplike.js
@@ -8,18 +8,17 @@
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 function TestInterfaceJSMaplike() {}
 
 TestInterfaceJSMaplike.prototype = {
   classID: Components.ID("{4bc6f6f3-e005-4f0a-b42d-4d1663a9013a}"),
   contractID: "@mozilla.org/dom/test-interface-js-maplike;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsIDOMGlobalPropertyInitializer]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer]),
 
   init: function(win) { this._win = win; },
 
   __init: function () {},
 
   setInternal: function(aKey, aValue) {
     return this.__DOM_IMPL__.__set(aKey, aValue);
   },
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -118,18 +118,18 @@ function BrowserElementChild() {
 
   this._isContentWindowCreated = false;
 
   this._init();
 };
 
 BrowserElementChild.prototype = {
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 
   _init: function() {
     debug("Starting up.");
 
     BrowserElementPromptService.mapWindowToBrowserElementChild(content, this);
 
     docShell.QueryInterface(Ci.nsIWebProgress)
             .addProgressListener(this._progressListener,
@@ -1375,18 +1375,18 @@ BrowserElementChild.prototype = {
     }
     this._finder.removeSelection();
     sendAsyncMsg("findchange", {active: false});
   },
 
   // The docShell keeps a weak reference to the progress listener, so we need
   // to keep a strong ref to it ourselves.
   _progressListener: {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                            Ci.nsISupportsWeakReference]),
     _seenLoadStart: false,
 
     onLocationChange: function(webProgress, request, location, flags) {
       // We get progress events from subshells here, which is kind of weird.
       if (webProgress != docShell) {
         return;
       }
 
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -69,19 +69,19 @@ function BrowserElementParent() {
   Services.obs.addObserver(this, 'back-docommand', /* ownsWeak = */ true);
 }
 
 BrowserElementParent.prototype = {
 
   classDescription: "BrowserElementAPI implementation",
   classID: Components.ID("{9f171ac4-0939-4ef8-b360-3408aedc3060}"),
   contractID: "@mozilla.org/dom/browser-element-api;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserElementAPI,
-                                         Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIBrowserElementAPI,
+                                          Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 
   setFrameLoader: function(frameLoader) {
     debug("Setting frameLoader");
     this._frameLoader = frameLoader;
     this._frameElement = frameLoader.ownerElement;
     if (!this._frameElement) {
       debug("No frame element?");
       return;
@@ -723,18 +723,18 @@ BrowserElementParent.prototype = {
           this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
         }
       },
       onDataAvailable: function(aRequest, aContext, aInputStream,
                                 aOffset, aCount) {
         this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
                                          aOffset, aCount);
       },
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener,
-                                             Ci.nsIRequestObserver])
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIStreamListener,
+                                              Ci.nsIRequestObserver])
     };
 
     let referrer = Services.io.newURI(_options.referrer);
     let principal =
       Services.scriptSecurityManager.createCodebasePrincipal(
         referrer, this._frameLoader.loadContext.originAttributes);
 
     let channel = NetUtil.newChannel({
--- a/dom/browser-element/BrowserElementPromptService.jsm
+++ b/dom/browser-element/BrowserElementPromptService.jsm
@@ -20,17 +20,17 @@ function debug(msg) {
 }
 
 function BrowserElementPrompt(win, browserElementChild) {
   this._win = win;
   this._browserElementChild = browserElementChild;
 }
 
 BrowserElementPrompt.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPrompt]),
 
   alert: function(title, text) {
     this._browserElementChild.showModalPrompt(
       this._win, {promptType: "alert", title: title, message: text, returnValue: undefined});
   },
 
   alertCheck: function(title, text, checkMsg, checkState) {
     // Treat this like a normal alert() call, ignoring the checkState.  The
@@ -207,17 +207,17 @@ BrowserElementPrompt.prototype = {
   },
 };
 
 
 function BrowserElementAuthPrompt() {
 }
 
 BrowserElementAuthPrompt.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAuthPrompt2]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIAuthPrompt2]),
 
   promptAuth: function promptAuth(channel, level, authInfo) {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
 
   asyncPromptAuth: function asyncPromptAuth(channel, callback, context, level, authInfo) {
     debug("asyncPromptAuth");
 
@@ -237,17 +237,17 @@ BrowserElementAuthPrompt.prototype = {
       BrowserElementPromptService.getBrowserElementParentForFrame(frame);
 
     if (!browserElementParent) {
       debug("Failed to load browser element parent.");
       throw Cr.NS_ERROR_FAILURE;
     }
 
     let consumer = {
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+      QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
       callback: callback,
       context: context,
       cancel: function() {
         this.callback.onAuthCancelled(this.context, false);
         this.callback = null;
         this.context = null;
       }
     };
@@ -436,17 +436,17 @@ BrowserElementAuthPrompt.prototype = {
 
 
 function AuthPromptWrapper(oldImpl, browserElementImpl) {
   this._oldImpl = oldImpl;
   this._browserElementImpl = browserElementImpl;
 }
 
 AuthPromptWrapper.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAuthPrompt2]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIAuthPrompt2]),
   promptAuth: function(channel, level, authInfo) {
     if (this._canGetParentElement(channel)) {
       return this._browserElementImpl.promptAuth(channel, level, authInfo);
     } else {
       return this._oldImpl.promptAuth(channel, level, authInfo);
     }
   },
 
@@ -478,17 +478,17 @@ AuthPromptWrapper.prototype = {
 };
 
 function BrowserElementPromptFactory(toWrap) {
   this._wrapped = toWrap;
 }
 
 BrowserElementPromptFactory.prototype = {
   classID: Components.ID("{24f3d0cf-e417-4b85-9017-c9ecf8bb1299}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptFactory]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPromptFactory]),
 
   _mayUseNativePrompt: function() {
     try {
       return Services.prefs.getBoolPref("browser.prompt.allowNative");
     } catch (e) {
       // This properity is default to true.
       return true;
     }
@@ -558,18 +558,18 @@ BrowserElementPromptFactory.prototype = 
 
     debug("Returning wrapped getPrompt for " + win);
     return new BrowserElementPrompt(win, browserElementChild)
                                    .QueryInterface(iid);
   }
 };
 
 var BrowserElementPromptService = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 
   _initialized: false,
 
   _init: function() {
     if (this._initialized) {
       return;
     }
 
--- a/dom/console/ConsoleAPIStorage.js
+++ b/dom/console/ConsoleAPIStorage.js
@@ -39,18 +39,18 @@ const CONSOLEAPISTORAGE_CID = Components
  *    ConsoleAPIStorage.clearEvents(innerWindowID);
  */
 function ConsoleAPIStorageService() {
   this.init();
 }
 
 ConsoleAPIStorageService.prototype = {
   classID : CONSOLEAPISTORAGE_CID,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleAPIStorage,
-                                         Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIConsoleAPIStorage,
+                                          Ci.nsIObserver]),
   classInfo: XPCOMUtils.generateCI({
     classID: CONSOLEAPISTORAGE_CID,
     contractID: '@mozilla.org/consoleAPI-storage;1',
     interfaces: [Ci.nsIConsoleAPIStorage, Ci.nsIObserver],
     flags: Ci.nsIClassInfo.SINGLETON
   }),
 
   observe: function CS_observe(aSubject, aTopic, aData)
--- a/dom/events/test/test_bug336682.js
+++ b/dom/events/test/test_bug336682.js
@@ -11,33 +11,16 @@ var gState = 0;
  */
 var MAX_STATE;
 
 function trace(text) {
   var t = text.replace(/&/g, "&" + "amp;").replace(/</g, "&" + "lt;") + "<br>";
   //document.getElementById("display").innerHTML += t;
 }
 
-// window.ononline and window.onclick shouldn't work
-// Right now, <body ononline=...> sets window.ononline (bug 380618)
-// When these start passing, be sure to uncomment the code inside if(0) below.
-todo(typeof window.ononline == "undefined",
-     "window.ononline should be undefined at this point");
-todo(typeof window.onoffline == "undefined",
-     "window.onoffline should be undefined at this point");
-
-if (0) {
-  window.ononline = function() {
-    ok(false, "window.ononline shouldn't be called");
-  }
-  window.onoffline = function() {
-    ok(false, "window.onclick shouldn't be called");
-  }
-}
-
 /**
  * Returns a handler function for an online/offline event. The returned handler
  * ensures the passed event object has expected properties and that the handler
  * is called at the right moment (according to the gState variable).
  * @param nameTemplate The string identifying the hanlder. '%1' in that
  *                     string will be replaced with the event name.
  * @param eventName 'online' or 'offline'
  * @param expectedStates an array listing the possible values of gState at the
@@ -50,21 +33,19 @@ function makeHandler(nameTemplate, event
     var name = nameTemplate.replace(/%1/, eventName);
     ++gState;
     trace(name + ": gState=" + gState);
     ok(expectedStates.includes(gState),
        "handlers called in the right order: " + name + " is called, " + 
        "gState=" + gState + ", expectedStates=" + expectedStates);
     ok(e.constructor == Event, "event should be an Event");
     ok(e.type == eventName, "event type should be " + eventName);
-    ok(e.bubbles, "event should bubble");
+    ok(!e.bubbles, "event should not bubble");
     ok(!e.cancelable, "event should not be cancelable");
-    ok(e.target == (document instanceof HTMLDocument
-                    ? document.body : document.documentElement),
-       "the event target should be the body element");
+    ok(e.target == window, "target should be the window");
   }
 }
 
 function doTest() {
   var iosvc = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
                            .getService(SpecialPowers.Ci.nsIIOService);
   iosvc.manageOfflineStatus = false;
   iosvc.offline = false;
--- a/dom/events/test/test_bug336682_1.html
+++ b/dom/events/test/test_bug336682_1.html
@@ -23,41 +23,31 @@ http://creativecommons.org/licenses/publ
 <pre id="test">
 </pre>
 <script type="text/javascript" src="test_bug336682.js"></script>
 
 <script class="testbody" type="text/javascript">
 
 function makeBodyHandler(eventName) {
   return function (aThis, aEvent) {
-    var handler = makeHandler("<body on%1='...'>", eventName, [3,4]);
+    var handler = makeHandler("<body on%1='...'>", eventName, [1]);
     handler(aEvent);
   }
 }
 addLoadEvent(function() {
   /** @see test_bug336682.js */
-  MAX_STATE = 4;
+  MAX_STATE = 2;
 
   for (var event of ["online", "offline"]) {
-    document.body.addEventListener(
-      event,
-      makeHandler("document.body.addEventListener('%1', ..., false)",
-                  event, [1]));
-
-    document.addEventListener(
-      event,
-      makeHandler("document.addEventListener('%1', ..., false)",
-                  event, [2]));
-
     window["bodyOn" + event] = makeBodyHandler(event);
 
     window.addEventListener(
       event,
       makeHandler("window.addEventListener('%1', ..., false)",
-                  event, [3,4]));
+                  event, [2]));
   }
 
   doTest();
   SimpleTest.finish();
 });
 
 SimpleTest.waitForExplicitFinish();
 </script>
--- a/dom/events/test/test_bug336682_2.xul
+++ b/dom/events/test/test_bug336682_2.xul
@@ -24,44 +24,32 @@ Mozilla Bug 336682 (online/offline event
 </div>
 </body>
 
 <script type="text/javascript" src="test_bug336682.js"/>
 <script class="testbody" type="text/javascript">
 <![CDATA[
 addLoadEvent(function() {
   /** @see test_bug336682.js */
-  MAX_STATE = 4;
+  MAX_STATE = 2;
 
   function makeWindowHandler(eventName) {
     return function (aThis, aEvent) {
-      var handler = makeHandler("<body on%1='...'>", eventName, [3,4]);
+      var handler = makeHandler("<body on%1='...'>", eventName, [1]);
       handler(aEvent);
     }
   }
 
   for (var event of ["online", "offline"]) {
-    document.documentElement.addEventListener(
-      event,
-      makeHandler("document.body.addEventListener('%1', ..., false)",
-                  event, [1]),
-      false);
-
-    document.addEventListener(
-      event,
-      makeHandler("document.addEventListener('%1', ..., false)",
-                  event, [2]),
-      false);
-
     window["windowOn" + event] = makeWindowHandler(event);
 
     window.addEventListener(
       event,
       makeHandler("window.addEventListener('%1', ..., false)",
-                  event, [3,4]),
+                  event, [2]),
       false);
   }
 
   doTest();
   SimpleTest.finish();
 });
 
 SimpleTest.waitForExplicitFinish();
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -779,17 +779,18 @@ HTMLFormElement::SubmitSubmission(HTMLFo
     NS_ENSURE_SUBMIT_SUCCESS(rv);
 
     rv = linkHandler->OnLinkClickSync(this, actionURI,
                                       target.get(),
                                       VoidString(),
                                       postDataStream, postDataStreamLength,
                                       nullptr, false,
                                       getter_AddRefs(docShell),
-                                      getter_AddRefs(mSubmittingRequest));
+                                      getter_AddRefs(mSubmittingRequest),
+                                      EventStateManager::IsHandlingUserInput());
     NS_ENSURE_SUBMIT_SUCCESS(rv);
   }
 
   // Even if the submit succeeds, it's possible for there to be no docshell
   // or request; for example, if it's to a named anchor within the same page
   // the submit will not really do anything.
   if (docShell) {
     // If the channel is pending, we have to listen for web progress.
--- a/dom/html/htmlMenuBuilder.js
+++ b/dom/html/htmlMenuBuilder.js
@@ -25,17 +25,17 @@ function HTMLMenuBuilder() {
 // other UI from this object. The default UI is done in PageMenu.jsm.
 //
 // When a multi-process browser is used, the first step is performed by the child
 // process and the second step is performed by the parent process.
 
 HTMLMenuBuilder.prototype =
 {
   classID:        Components.ID("{51c65f5d-0de5-4edc-9058-60e50cef77f8}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIMenuBuilder]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIMenuBuilder]),
 
   currentNode: null,
   root: null,
   items: {},
   nestedStack: [],
 
   toJSONString: function() {
     return JSON.stringify(this.root);
--- a/dom/html/test/head.js
+++ b/dom/html/test/head.js
@@ -33,18 +33,18 @@ function waitForDocLoadComplete(aBrowser
         if ((flags & docStop) == docStop && status != Cr.NS_BINDING_ABORTED) {
           aBrowser.removeProgressListener(this);
           waitForDocLoadComplete.listeners.delete(this);
           let chan = req.QueryInterface(Ci.nsIChannel);
           info("Browser loaded " + chan.originalURI.spec);
           resolve();
         }
       },
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                             Ci.nsISupportsWeakReference])
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                              Ci.nsISupportsWeakReference])
     };
     aBrowser.addProgressListener(listener);
     waitForDocLoadComplete.listeners.add(listener);
     info("Waiting for browser load");
   });
 }
 // Keep a set of progress listeners for waitForDocLoadComplete() to make sure
 // they're not GC'ed before we saw the page load.
--- a/dom/indexedDB/test/unit/GlobalObjectsComponent.js
+++ b/dom/indexedDB/test/unit/GlobalObjectsComponent.js
@@ -9,17 +9,17 @@ Cu.importGlobalProperties(["indexedDB"])
 function GlobalObjectsComponent() {
   this.wrappedJSObject = this;
 }
 
 GlobalObjectsComponent.prototype =
 {
   classID: Components.ID("{949ebf50-e0da-44b9-8335-cbfd4febfdcc}"),
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
+  QueryInterface: ChromeUtils.generateQI([]),
 
   runTest() {
     const name = "Splendid Test";
 
     let ok = this.ok;
     let finishTest = this.finishTest;
 
     let keyRange = IDBKeyRange.only(42);
--- a/dom/media/IdpSandbox.jsm
+++ b/dom/media/IdpSandbox.jsm
@@ -18,17 +18,17 @@ RedirectHttpsOnly.prototype = {
     } else {
       callback.onRedirectVerifyCallback(Cr.NS_OK);
     }
   },
 
   getInterface(iid) {
     return this.QueryInterface(iid);
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIChannelEventSink])
 };
 
 /** This class loads a resource into a single string. ResourceLoader.load() is
  * the entry point. */
 function ResourceLoader(res, rej) {
   this.resolve = res;
   this.reject = rej;
   this.data = "";
@@ -72,17 +72,17 @@ ResourceLoader.prototype = {
     } else {
       this.reject(new Error("Load failed: " + status));
     }
   },
 
   getInterface(iid) {
     return this.QueryInterface(iid);
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIStreamListener])
 };
 
 /**
  * A simple implementation of the WorkerLocation interface.
  */
 function createLocationFromURI(uri) {
   return {
     href: uri.spec,
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -198,18 +198,18 @@ class GlobalPCList {
     }
   }
 
   _registerPeerConnectionLifecycleCallback(winID, cb) {
     this._lifecycleobservers[winID] = cb;
   }
 }
 setupPrototype(GlobalPCList, {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
   classID: PC_MANAGER_CID,
   _xpcom_factory: {
     createInstance(outer, iid) {
       if (outer) {
         throw Cr.NS_ERROR_NO_AGGREGATION;
       }
       return _globalPCList.QueryInterface(iid);
     }
@@ -225,18 +225,17 @@ class RTCIceCandidate {
 
   __init(dict) {
     Object.assign(this, dict);
   }
 }
 setupPrototype(RTCIceCandidate, {
   classID: PC_ICE_CID,
   contractID: PC_ICE_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsIDOMGlobalPropertyInitializer])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer])
 });
 
 class RTCSessionDescription {
   init(win) {
     this._win = win;
     this._winID = this._win.QueryInterface(Ci.nsIInterfaceRequestor)
     .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
   }
@@ -270,18 +269,17 @@ class RTCSessionDescription {
     let err = this._win.Error();
     logMsg(msg, err.fileName, err.lineNumber, Ci.nsIScriptError.warningFlag,
            this._winID);
   }
 }
 setupPrototype(RTCSessionDescription, {
   classID: PC_SESSION_CID,
   contractID: PC_SESSION_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsIDOMGlobalPropertyInitializer])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer])
 });
 
 class RTCStatsReport {
   constructor(win, dict) {
     this._win = win;
     this._pcid = dict.pcid;
     this._report = convertToRTCStatsReport(dict);
   }
@@ -325,17 +323,17 @@ class RTCStatsReport {
 
   __onget(key, value) {
     /* Do whatever here */
   }
 }
 setupPrototype(RTCStatsReport, {
   classID: PC_STATS_CID,
   contractID: PC_STATS_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
+  QueryInterface: ChromeUtils.generateQI([]),
   _specToLegacyFieldMapping: {
         "inbound-rtp": "inboundrtp",
         "outbound-rtp": "outboundrtp",
         "candidate-pair": "candidatepair",
         "local-candidate": "localcandidate",
         "remote-candidate": "remotecandidate"
   }
 });
@@ -1602,18 +1600,17 @@ class RTCPeerConnection {
     this.updateNegotiationNeeded();
 
     return dataChannel;
   }
 }
 setupPrototype(RTCPeerConnection, {
   classID: PC_CID,
   contractID: PC_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsIDOMGlobalPropertyInitializer]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer]),
   _actions: {
     offer: Ci.IPeerConnection.kActionOffer,
     answer: Ci.IPeerConnection.kActionAnswer,
     pranswer: Ci.IPeerConnection.kActionPRAnswer,
     rollback: Ci.IPeerConnection.kActionRollback,
   },
 });
 
@@ -1861,35 +1858,33 @@ class PeerConnectionObserver {
 
   syncTransceivers() {
     this._dompc._syncTransceivers();
   }
 }
 setupPrototype(PeerConnectionObserver, {
   classID: PC_OBS_CID,
   contractID: PC_OBS_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsIDOMGlobalPropertyInitializer])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer])
 });
 
 class RTCPeerConnectionStatic {
   init(win) {
     this._winID = win.QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
   }
 
   registerPeerConnectionLifecycleCallback(cb) {
     _globalPCList._registerPeerConnectionLifecycleCallback(this._winID, cb);
   }
 }
 setupPrototype(RTCPeerConnectionStatic, {
   classID: PC_STATIC_CID,
   contractID: PC_STATIC_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
-                                         Ci.nsIDOMGlobalPropertyInitializer])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer])
 });
 
 class RTCDTMFSender {
   constructor(sender) {
     this._sender = sender;
   }
 
   get toneBuffer() {
@@ -1907,17 +1902,17 @@ class RTCDTMFSender {
   insertDTMF(tones, duration, interToneGap) {
     this._sender._pc._checkClosed();
     this._sender._transceiver.insertDTMF(tones, duration, interToneGap);
   }
 }
 setupPrototype(RTCDTMFSender, {
   classID: PC_DTMF_SENDER_CID,
   contractID: PC_DTMF_SENDER_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports])
+  QueryInterface: ChromeUtils.generateQI([])
 });
 
 class RTCRtpSender {
   constructor(pc, transceiverImpl, transceiver, track, kind, streams) {
     let dtmf = null;
     if (kind == "audio") {
       dtmf = pc._win.RTCDTMFSender._create(pc._win, new RTCDTMFSender(this));
     }
@@ -2049,17 +2044,17 @@ class RTCRtpSender {
           "This sender was not created by this PeerConnection",
           "InvalidAccessError");
     }
   }
 }
 setupPrototype(RTCRtpSender, {
   classID: PC_SENDER_CID,
   contractID: PC_SENDER_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports])
+  QueryInterface: ChromeUtils.generateQI([])
 });
 
 class RTCRtpReceiver {
   constructor(pc, transceiverImpl) {
     // We do not set the track here; that is done when _transceiverImpl is set
     Object.assign(this,
         {
           _pc: pc,
@@ -2219,17 +2214,17 @@ class RTCRtpReceiver {
           { track: this.track });
       trackEvents.push(ev);
     }
   }
 }
 setupPrototype(RTCRtpReceiver, {
   classID: PC_RECEIVER_CID,
   contractID: PC_RECEIVER_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports])
+  QueryInterface: ChromeUtils.generateQI([])
 });
 
 class RTCRtpTransceiver {
   constructor(pc, transceiverImpl, init, kind, sendTrack) {
     let receiver = pc._win.RTCRtpReceiver._create(
         pc._win, new RTCRtpReceiver(pc, transceiverImpl, kind));
     let streams = (init && init.streams) || [];
     let sender = pc._win.RTCRtpSender._create(
@@ -2382,28 +2377,28 @@ class RTCRtpTransceiver {
     // extra hops through RTCPeerConnection and PeerConnectionImpl
     this._pc._insertDTMF(this._transceiverImpl, tones, duration, interToneGap);
   }
 }
 
 setupPrototype(RTCRtpTransceiver, {
   classID: PC_TRANSCEIVER_CID,
   contractID: PC_TRANSCEIVER_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports])
+  QueryInterface: ChromeUtils.generateQI([])
 });
 
 class CreateOfferRequest {
   constructor(windowID, innerWindowID, callID, isSecure) {
     Object.assign(this, { windowID, innerWindowID, callID, isSecure });
   }
 }
 setupPrototype(CreateOfferRequest, {
   classID: PC_COREQUEST_CID,
   contractID: PC_COREQUEST_CONTRACT,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports])
+  QueryInterface: ChromeUtils.generateQI([])
 });
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
   [GlobalPCList,
    RTCDTMFSender,
    RTCIceCandidate,
    RTCSessionDescription,
    RTCPeerConnection,
--- a/dom/media/webvtt/WebVTTParserWrapper.js
+++ b/dom/media/webvtt/WebVTTParserWrapper.js
@@ -54,17 +54,17 @@ WebVTTParserWrapper.prototype =
 
   processCues: function(window, cues, overlay, controls)
   {
     WebVTT.processCues(window, cues, overlay, controls);
   },
 
   classDescription: "Wrapper for the JS WebVTT implementation (vtt.js)",
   classID: Components.ID(WEBVTTPARSERWRAPPER_CID),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebVTTParserWrapper]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebVTTParserWrapper]),
   classInfo: XPCOMUtils.generateCI({
     classID:    WEBVTTPARSERWRAPPER_CID,
     contractID: WEBVTTPARSERWRAPPER_CONTRACTID,
     interfaces: [Ci.nsIWebVTTParserWrapper]
   })
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebVTTParserWrapper]);
--- a/dom/notification/NotificationStorage.js
+++ b/dom/notification/NotificationStorage.js
@@ -251,13 +251,13 @@ NotificationStorage.prototype = {
         this._byTag[origin][tag] = notification;
       }
     });
     this._cached = true;
   },
 
   classID : Components.ID(NOTIFICATIONSTORAGE_CID),
   contractID : NOTIFICATIONSTORAGE_CONTRACTID,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsINotificationStorage]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsINotificationStorage]),
 };
 
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NotificationStorage]);
--- a/dom/payments/test/BasiccardChromeScript.js
+++ b/dom/payments/test/BasiccardChromeScript.js
@@ -69,17 +69,17 @@ const detailedResponseUI = {
                       "",                   // payer email
                       "");                  // payer phone
     paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
   abortPayment: abortPaymentResponse,
   completePayment: completePaymentResponse,
   updatePayment: function(requestId) {
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 const simpleResponseUI = {
   showPayment: function(requestId) {
     try {
       basiccardResponseData.initData("",                 // cardholderName
                                      "4916855166538720", // cardNumber
                                      "",                 // expiryMonth
@@ -97,17 +97,17 @@ const simpleResponseUI = {
                       "",                   // payer email
                       "");                  // payer phone
     paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
   abortPayment: abortPaymentResponse,
   completePayment: completePaymentResponse,
   updatePayment: function(requestId) {
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 addMessageListener("set-detailed-ui-service", function() {
   paymentSrv.setTestingUIService(detailedResponseUI.QueryInterface(Ci.nsIPaymentUIService));
 });
 
 addMessageListener("set-simple-ui-service", function() {
   paymentSrv.setTestingUIService(simpleResponseUI.QueryInterface(Ci.nsIPaymentUIService));
--- a/dom/payments/test/CurrencyAmountValidationChromeScript.js
+++ b/dom/payments/test/CurrencyAmountValidationChromeScript.js
@@ -16,17 +16,17 @@ const InvalidDetailsUIService = {
                            createInstance(Ci.nsIPaymentAbortActionResponse);
     abortResponse.init(requestId, Ci.nsIPaymentActionResponse.ABORT_SUCCEEDED);
     paymentSrv.respondPayment(abortResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
   completePayment: function(requestId) {
   },
   updatePayment: function(requestId) {
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 
 };
 
 function emitTestFail(message) {
   sendAsyncMessage("test-fail", message);
 }
 
 function checkLowerCaseCurrency() {
--- a/dom/payments/test/PMIValidationChromeScript.js
+++ b/dom/payments/test/PMIValidationChromeScript.js
@@ -34,17 +34,17 @@ const UIService = {
                       Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
                       "https://example.com",   // payment method
                       showResponseData,           // payment method data
                       "Bill A. Pacheco",          // payer name
                       "",                         // payer email
                       "");                        // payer phone
     paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 function emitTestFail(message) {
   sendAsyncMessage("test-fail", message);
 }
 
 addMessageListener("set-ui-service", function() {
   paymentSrv.setTestingUIService(UIService.QueryInterface(Ci.nsIPaymentUIService));
--- a/dom/payments/test/RequestShippingChromeScript.js
+++ b/dom/payments/test/RequestShippingChromeScript.js
@@ -66,17 +66,17 @@ const NormalUIService = {
                       Ci.nsIPaymentActionResponse.PAYMENT_ACCEPTED,
                       "testing-payment-method",   // payment method
                       showResponseData,           // payment method data
                       "",                         // payer name
                       "",                         // payer email
                       "");                        // payer phone
     paymentSrv.respondPayment(showResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 addMessageListener("set-normal-ui-service", function() {
   paymentSrv.setTestingUIService(NormalUIService.QueryInterface(Ci.nsIPaymentUIService));
 });
 
 addMessageListener("teardown", function() {
   paymentSrv.cleanup();
--- a/dom/payments/test/ShippingOptionsChromeScript.js
+++ b/dom/payments/test/ShippingOptionsChromeScript.js
@@ -69,17 +69,17 @@ const TestingUIService = {
   completePayment: function(requestId) {
     let request = paymentSrv.getPaymentRequestById(requestId);
     let completeResponse = Cc["@mozilla.org/dom/payments/payment-complete-action-response;1"].
                            createInstance(Ci.nsIPaymentCompleteActionResponse);
     completeResponse.init(requestId, Ci.nsIPaymentActionResponse.COMPLETE_SUCCEEDED);
     paymentSrv.respondPayment(completeResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
   updatePayment: updateRequest,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 paymentSrv.setTestingUIService(TestingUIService.QueryInterface(Ci.nsIPaymentUIService));
 
 addMessageListener("set-expected-results", function(results) {
   expectedRequestOption = results.requestResult;
   expectedUpdatedOption = results.responseResult;
   changeShippingOption = results.changeOptionResult;
--- a/dom/payments/test/ShowPaymentChromeScript.js
+++ b/dom/payments/test/ShowPaymentChromeScript.js
@@ -145,17 +145,17 @@ function updateRequest(requestId) {
   }
 }
 
 const DummyUIService = {
   showPayment: showRequest,
   abortPayment: abortRequest,
   completePayment: completeRequest,
   updatePayment: updateRequest,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPaymentUIService]),
 };
 
 paymentSrv.setTestingUIService(DummyUIService.QueryInterface(Ci.nsIPaymentUIService));
 
 function testShowResponseInit() {
   const showResponseData = Cc["@mozilla.org/dom/payments/general-response-data;1"].
                               createInstance(Ci.nsIGeneralResponseData);
   try {
--- a/dom/performance/PerformanceTiming.h
+++ b/dom/performance/PerformanceTiming.h
@@ -435,16 +435,30 @@ public:
     if (mPerformance->IsSystemPrincipal()) {
       return GetDOMTiming()->GetTimeToNonBlankPaint();
     }
     return nsRFPService::ReduceTimePrecisionAsMSecs(
       GetDOMTiming()->GetTimeToNonBlankPaint(),
       mPerformance->GetRandomTimelineSeed());
   }
 
+  DOMTimeMilliSec TimeToDOMContentFlushed() const
+  {
+    if (!nsContentUtils::IsPerformanceTimingEnabled() ||
+        nsContentUtils::ShouldResistFingerprinting()) {
+      return 0;
+    }
+    if (mPerformance->IsSystemPrincipal()) {
+      return GetDOMTiming()->GetTimeToDOMContentFlushed();
+    }
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      GetDOMTiming()->GetTimeToDOMContentFlushed(),
+      mPerformance->GetRandomTimelineSeed());
+  }
+
   PerformanceTimingData* Data() const
   {
     return mTimingData.get();
   }
 
 private:
   ~PerformanceTiming();
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -480,17 +480,19 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
   nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   if (!aDoCheckLoadURIChecks) {
     mozilla::OriginAttributes attrs =
       BasePrincipal::Cast(content->NodePrincipal())->OriginAttributesRef();
     triggeringPrincipal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
   }
 
   rv = lh->OnLinkClick(content, uri, unitarget.get(), VoidString(),
-                       aPostStream, -1, headersDataStream, true, triggeringPrincipal);
+                       aPostStream, -1, headersDataStream,
+                       /* isUserTriggered */ false,
+                       /* isTrusted */ true, triggeringPrincipal);
 
   return rv;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(nsIDocument* *aDocument)
 {
   nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
   if (!aDocument || !content) {
--- a/dom/presentation/PresentationDataChannelSessionTransport.js
+++ b/dom/presentation/PresentationDataChannelSessionTransport.js
@@ -18,17 +18,17 @@ const PRESENTATIONTRANSPORT_CONTRACTID =
 const PRESENTATIONTRANSPORTBUILDER_CID = Components.ID("{215b2f62-46e2-4004-a3d1-6858e56c20f3}");
 const PRESENTATIONTRANSPORTBUILDER_CONTRACTID = "mozilla.org/presentation/datachanneltransportbuilder;1";
 
 function PresentationDataChannelDescription(aDataChannelSDP) {
   this._dataChannelSDP = JSON.stringify(aDataChannelSDP);
 }
 
 PresentationDataChannelDescription.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationChannelDescription]),
   get type() {
     return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
   },
   get tcpAddress() {
     return null;
   },
   get tcpPort() {
     return null;
@@ -41,19 +41,19 @@ PresentationDataChannelDescription.proto
 function PresentationTransportBuilder() {
   log("PresentationTransportBuilder construct");
   this._isControlChannelNeeded = true;
 }
 
 PresentationTransportBuilder.prototype = {
   classID: PRESENTATIONTRANSPORTBUILDER_CID,
   contractID: PRESENTATIONTRANSPORTBUILDER_CONTRACTID,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilder,
-                                         Ci.nsIPresentationDataChannelSessionTransportBuilder,
-                                         Ci.nsITimerCallback]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransportBuilder,
+                                          Ci.nsIPresentationDataChannelSessionTransportBuilder,
+                                          Ci.nsITimerCallback]),
 
   buildDataChannelTransport: function(aRole, aWindow, aListener) {
     if (!aRole || !aWindow || !aListener) {
       log("buildDataChannelTransport with illegal parameters");
       throw Cr.NS_ERROR_ILLEGAL_VALUE;
     }
 
     if (this._window) {
@@ -240,17 +240,17 @@ PresentationTransportBuilder.prototype =
 function PresentationTransport() {
   this._messageQueue = [];
   this._closeReason = Cr.NS_OK;
 }
 
 PresentationTransport.prototype = {
   classID: PRESENTATIONTRANSPORT_CID,
   contractID: PRESENTATIONTRANSPORT_CONTRACTID,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransport]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransport]),
 
   init: function(aPeerConnection, aDataChannel, aWindow) {
     log("initWithDataChannel");
     this._enableDataNotification = false;
     this._dataChannel = aDataChannel;
     this._peerConnection = aPeerConnection;
     this._window = aWindow;
 
--- a/dom/presentation/PresentationNetworkHelper.js
+++ b/dom/presentation/PresentationNetworkHelper.js
@@ -9,17 +9,17 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const NETWORKHELPER_CID = Components.ID("{5fb96caa-6d49-4f6b-9a4b-65dd0d51f92d}");
 
 function PresentationNetworkHelper() {}
 
 PresentationNetworkHelper.prototype = {
   classID: NETWORKHELPER_CID,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationNetworkHelper]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationNetworkHelper]),
 
   getWifiIPAddress: function(aListener) {
     EventDispatcher.instance.sendRequestForResult({type: "Wifi:GetIPAddress"})
              .then(result => aListener.onGetWifiIPAddress(result),
                    err => aListener.onError(err));
   }
 };
 
--- a/dom/presentation/provider/AndroidCastDeviceProvider.js
+++ b/dom/presentation/provider/AndroidCastDeviceProvider.js
@@ -255,17 +255,17 @@ LocalControlChannel.prototype = {
   },
 
   reconnect: function LCC_reconnect(aPresentationId, aUrl) {
     log("1-UA on Android doesn't support reconnect.");
     throw Cr.NS_ERROR_FAILURE;
   },
 
   classID: Components.ID("{c9be9450-e5c7-4294-a287-376971b017fd}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel]),
 };
 
 function ChromecastRemoteDisplayDevice(aProvider, aId, aName, aRole) {
   this._provider = aProvider;
   this._id       = aId;
   this._name     = aName;
   this._role     = aRole;
 }
@@ -344,20 +344,20 @@ ChromecastRemoteDisplayDevice.prototype 
           + aTopic + " data=" + aData);
       if (this.windowId === aData) {
         Services.obs.removeObserver(this, TOPIC_PRESENTATION_VIEW_READY);
         this._ctrlChannel.notifyConnected();
       }
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice,
-                                         Ci.nsIPresentationLocalDevice,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevice,
+                                          Ci.nsIPresentationLocalDevice,
+                                          Ci.nsISupportsWeakReference,
+                                          Ci.nsIObserver]),
 };
 
 function AndroidCastDeviceProvider() {
   this._listener = null;
   this._deviceList = new Map();
 }
 
 AndroidCastDeviceProvider.prototype = {
@@ -458,13 +458,13 @@ AndroidCastDeviceProvider.prototype = {
         this._listener.removeDevice(device);
         this._deviceList.delete(deviceId);
         break;
       }
     }
   },
 
   classID: Components.ID("{7394f24c-dbc3-48c8-8a47-cd10169b7c6b}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsIPresentationDeviceProvider]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsIPresentationDeviceProvider]),
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AndroidCastDeviceProvider]);
--- a/dom/presentation/provider/PresentationControlService.js
+++ b/dom/presentation/provider/PresentationControlService.js
@@ -353,19 +353,19 @@ PresentationControlService.prototype = {
         this.startServer();
       } catch (e) {
         DEBUG && log("PresentationControlService - restart service fail: " + e); // jshint ignore:line
       }
     }
   },
 
   classID: Components.ID("{f4079b8b-ede5-4b90-a112-5b415a931deb}"),
-  QueryInterface : XPCOMUtils.generateQI([Ci.nsIServerSocketListener,
-                                          Ci.nsIPresentationControlService,
-                                          Ci.nsIObserver]),
+  QueryInterface : ChromeUtils.generateQI([Ci.nsIServerSocketListener,
+                                           Ci.nsIPresentationControlService,
+                                           Ci.nsIObserver]),
 };
 
 function ChannelDescription(aInit) {
   this._type = aInit.type;
   switch (this._type) {
     case Ci.nsIPresentationChannelDescription.TYPE_TCP:
       this._tcpAddresses = Cc["@mozilla.org/array;1"]
                            .createInstance(Ci.nsIMutableArray);
@@ -402,17 +402,17 @@ ChannelDescription.prototype = {
     return this._tcpPort;
   },
 
   get dataChannelSDP() {
     return this._dataChannelSDP;
   },
 
   classID: Components.ID("{82507aea-78a2-487e-904a-858a6c5bf4e1}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationChannelDescription]),
 };
 
 // Helper function: transfer nsIPresentationChannelDescription to json
 function discriptionAsJson(aDescription) {
   let json = {};
   json.type = aDescription.type;
   switch(aDescription.type) {
     case Ci.nsIPresentationChannelDescription.TYPE_TCP:
@@ -947,13 +947,13 @@ TCPControlChannel.prototype = {
     this._onAnswer(answer);
   },
 
   notifyIceCandidate: function(candidate) {
     this._listener.onIceCandidate(candidate);
   },
 
   classID: Components.ID("{fefb8286-0bdc-488b-98bf-0c11b485c955}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel,
-                                         Ci.nsIStreamListener]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel,
+                                          Ci.nsIStreamListener]),
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationControlService]); // jshint ignore:line
--- a/dom/presentation/tests/mochitest/PresentationDeviceInfoChromeScript.js
+++ b/dom/presentation/tests/mochitest/PresentationDeviceInfoChromeScript.js
@@ -4,82 +4,82 @@
 'use strict';
 
 const { XPCOMUtils } = ChromeUtils.import('resource://gre/modules/XPCOMUtils.jsm');
 
 const manager = Cc['@mozilla.org/presentation-device/manager;1']
                   .getService(Ci.nsIPresentationDeviceManager);
 
 var testProvider = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceProvider]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceProvider]),
   forceDiscovery: function() {
     sendAsyncMessage('force-discovery');
   },
   listener: null,
 };
 
 var testDevice = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevice]),
   establishControlChannel: function() {
     return null;
   },
   disconnect: function() {},
   isRequestedUrlSupported: function(requestedUrl) {
     return true;
   },
   id: null,
   name: null,
   type: null,
   listener: null,
 };
 
 var testDevice1 = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevice]),
   id: 'dummyid',
   name: 'dummyName',
   type: 'dummyType',
   establishControlChannel: function(url, presentationId) {
     return null;
   },
   disconnect: function() {},
   isRequestedUrlSupported: function(requestedUrl) {
     return true;
   },
 };
 
 var testDevice2 = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevice]),
   id: 'dummyid',
   name: 'dummyName',
   type: 'dummyType',
   establishControlChannel: function(url, presentationId) {
     return null;
   },
   disconnect: function() {},
   isRequestedUrlSupported: function(requestedUrl) {
     return true;
   },
 };
 
 var mockedDeviceWithoutSupportedURL = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevice]),
   id: 'dummyid',
   name: 'dummyName',
   type: 'dummyType',
   establishControlChannel: function(url, presentationId) {
     return null;
   },
   disconnect: function() {},
   isRequestedUrlSupported: function(requestedUrl) {
     return false;
   },
 };
 
 var mockedDeviceSupportHttpsURL = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevice]),
   id: 'dummyid',
   name: 'dummyName',
   type: 'dummyType',
   establishControlChannel: function(url, presentationId) {
     return null;
   },
   disconnect: function() {},
   isRequestedUrlSupported: function(requestedUrl) {
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
@@ -49,30 +49,30 @@ var sessionId = 'test-session-id-' + uui
 
 const address = Cc["@mozilla.org/supports-cstring;1"]
                   .createInstance(Ci.nsISupportsCString);
 address.data = "127.0.0.1";
 const addresses = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
 addresses.appendElement(address);
 
 const mockedChannelDescription = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationChannelDescription]),
   get type() {
     if (Services.prefs.getBoolPref("dom.presentation.session_transport.data_channel.enable")) {
       return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
     }
     return Ci.nsIPresentationChannelDescription.TYPE_TCP;
   },
   tcpAddress: addresses,
   tcpPort: 1234,
 };
 
 const mockedServerSocket = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIServerSocket,
-                                         Ci.nsIFactory]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIServerSocket,
+                                          Ci.nsIFactory]),
   createInstance: function(aOuter, aIID) {
     if (aOuter) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
     return this.QueryInterface(aIID);
   },
   get port() {
     return this._port;
@@ -94,21 +94,21 @@ const mockedServerSocket = {
     this._listener.onStopListening(this, Cr.NS_BINDING_ABORTED);
   },
   simulateOnSocketAccepted: function(serverSocket, socketTransport) {
     this._listener.onSocketAccepted(serverSocket, socketTransport);
   }
 };
 
 const mockedSocketTransport = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISocketTransport]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsISocketTransport]),
 };
 
 const mockedControlChannel = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel]),
   set listener(listener) {
     this._listener = listener;
   },
   get listener() {
     return this._listener;
   },
   sendOffer: function(offer) {
     sendAsyncMessage('offer-sent', this._isValidSDP(offer));
@@ -172,33 +172,33 @@ const mockedControlChannel = {
   },
   simulateNotifyConnected: function() {
     sendAsyncMessage('control-channel-opened');
     this._listener.QueryInterface(Ci.nsIPresentationControlChannelListener).notifyConnected();
   },
 };
 
 const mockedDevice = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevice]),
   id: 'id',
   name: 'name',
   type: 'type',
   establishControlChannel: function(url, presentationId) {
     sendAsyncMessage('control-channel-established');
     return mockedControlChannel;
   },
   disconnect: function() {},
   isRequestedUrlSupported: function(requestedUrl) {
     return true;
   },
 };
 
 const mockedDevicePrompt = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt,
-                                         Ci.nsIFactory]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevicePrompt,
+                                          Ci.nsIFactory]),
   createInstance: function(aOuter, aIID) {
     if (aOuter) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
     return this.QueryInterface(aIID);
   },
   set request(request) {
     this._request = request;
@@ -214,22 +214,22 @@ const mockedDevicePrompt = {
     this._request.select(mockedDevice);
   },
   simulateCancel: function(result) {
     this._request.cancel(result);
   }
 };
 
 const mockedSessionTransport = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransport,
-                                         Ci.nsIPresentationSessionTransportBuilder,
-                                         Ci.nsIPresentationTCPSessionTransportBuilder,
-                                         Ci.nsIPresentationDataChannelSessionTransportBuilder,
-                                         Ci.nsIPresentationControlChannelListener,
-                                         Ci.nsIFactory]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransport,
+                                          Ci.nsIPresentationSessionTransportBuilder,
+                                          Ci.nsIPresentationTCPSessionTransportBuilder,
+                                          Ci.nsIPresentationDataChannelSessionTransportBuilder,
+                                          Ci.nsIPresentationControlChannelListener,
+                                          Ci.nsIFactory]),
   createInstance: function(aOuter, aIID) {
     if (aOuter) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
     return this.QueryInterface(aIID);
   },
   set callback(callback) {
     this._callback = callback;
@@ -252,17 +252,17 @@ const mockedSessionTransport = {
     }, 0);
   },
   buildTCPReceiverTransport: function(description, listener) {
     this._listener = listener;
     this._role = Ci.nsIPresentationService.ROLE_RECEIVER;
 
     var addresses = description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpAddress;
     this._selfAddress = {
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsINetAddr]),
+      QueryInterface: ChromeUtils.generateQI([Ci.nsINetAddr]),
       address: (addresses.length > 0) ?
                 addresses.queryElementAt(0, Ci.nsISupportsCString).data : "",
       port: description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpPort,
     };
 
     setTimeout(()=>{
       this._listener.onSessionTransport(this);
       this._listener = null;
@@ -303,43 +303,43 @@ const mockedSessionTransport = {
   },
   onOffer: function(aOffer) {
   },
   onAnswer: function(aAnswer) {
   }
 };
 
 const mockedNetworkInfo = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInfo]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsINetworkInfo]),
   getAddresses: function(ips, prefixLengths) {
     ips.value = ["127.0.0.1"];
     prefixLengths.value = [0];
     return 1;
   },
 };
 
 const mockedNetworkManager = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkManager,
-                                         Ci.nsIFactory]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsINetworkManager,
+                                          Ci.nsIFactory]),
   createInstance: function(aOuter, aIID) {
     if (aOuter) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
     return this.QueryInterface(aIID);
   },
   get activeNetworkInfo() {
     return mockedNetworkInfo;
   },
 };
 
 var requestPromise = null;
 
 const mockedRequestUIGlue = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationRequestUIGlue,
-                                         Ci.nsIFactory]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationRequestUIGlue,
+                                          Ci.nsIFactory]),
   createInstance: function(aOuter, aIID) {
     if (aOuter) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
     return this.QueryInterface(aIID);
   },
   sendRequest: function(aUrl, aSessionId) {
     sendAsyncMessage('receiver-launching', aSessionId);
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
@@ -18,17 +18,17 @@ function debug(str) {
 }
 
 const originalFactoryData = [];
 var sessionId; // Store the uuid generated by PresentationRequest.
 var triggerControlChannelError = false; // For simulating error during control channel establishment.
 
 // control channel of sender
 const mockControlChannelOfSender = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel]),
   set listener(listener) {
     // PresentationControllingInfo::SetControlChannel
     if (listener) {
       debug('set listener for mockControlChannelOfSender without null');
     } else {
       debug('set listener for mockControlChannelOfSender with null');
     }
     this._listener = listener;
@@ -88,17 +88,17 @@ const mockControlChannelOfSender = {
     this._listener
         .QueryInterface(Ci.nsIPresentationControlChannelListener)
         .onIceCandidate(candidate);
   },
 };
 
 // control channel of receiver
 const mockControlChannelOfReceiver = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel]),
   set listener(listener) {
     // PresentationPresentingInfo::SetControlChannel
     if (listener) {
       debug('set listener for mockControlChannelOfReceiver without null');
     } else {
       debug('set listener for mockControlChannelOfReceiver with null');
     }
     this._listener = listener;
@@ -153,17 +153,17 @@ const mockControlChannelOfReceiver = {
 
     this._listener
         .QueryInterface(Ci.nsIPresentationControlChannelListener)
         .onIceCandidate(candidate);
   },
 };
 
 const mockDevice = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevice]),
   id:   'id',
   name: 'name',
   type: 'type',
   establishControlChannel: function(url, presentationId) {
     if (triggerControlChannelError) {
       throw Cr.NS_ERROR_FAILURE;
     }
     sendAsyncMessage('control-channel-established');
@@ -173,18 +173,18 @@ const mockDevice = {
     sendAsyncMessage('device-disconnected');
   },
   isRequestedUrlSupported: function(requestedUrl) {
     return true;
   },
 };
 
 const mockDevicePrompt = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt,
-                                         Ci.nsIFactory]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevicePrompt,
+                                          Ci.nsIFactory]),
   createInstance: function(aOuter, aIID) {
     if (aOuter) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
     return this.QueryInterface(aIID);
   },
   set request(request) {
     this._request = request;
@@ -200,18 +200,18 @@ const mockDevicePrompt = {
     this._request.select(mockDevice);
   },
   simulateCancel: function() {
     this._request.cancel();
   }
 };
 
 const mockRequestUIGlue = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationRequestUIGlue,
-                                         Ci.nsIFactory]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationRequestUIGlue,
+                                          Ci.nsIFactory]),
   set promise(aPromise) {
     this._promise = aPromise
   },
   get promise() {
     return this._promise;
   },
   createInstance: function(aOuter, aIID) {
     if (aOuter) {
--- a/dom/presentation/tests/mochitest/test_presentation_datachannel_sessiontransport.html
+++ b/dom/presentation/tests/mochitest/test_presentation_datachannel_sessiontransport.html
@@ -37,17 +37,17 @@ var isClientReady = false;
 var isServerReady = false;
 var isClientClosed = false;
 var isServerClosed = false;
 
 var gResolve;
 var gReject;
 
 const clientCallback = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
   notifyTransportReady: function () {
     info("Client transport ready.");
 
     isClientReady = true;
     if (isClientReady && isServerReady) {
       gResolve();
     }
   },
@@ -61,17 +61,17 @@ const clientCallback = {
   },
   notifyData: function(aData) {
     is(aData, serverMessage, "Client transport receives data.");
     gResolve();
   },
 };
 
 const serverCallback = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
   notifyTransportReady: function () {
     info("Server transport ready.");
 
     isServerReady = true;
     if (isClientReady && isServerReady) {
       gResolve();
     }
   },
@@ -85,17 +85,17 @@ const serverCallback = {
   },
   notifyData: function(aData) {
     is(aData, clientMessage, "Server transport receives data.");
     gResolve()
   },
 };
 
 const clientListener = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
   onSessionTransport: function(aTransport) {
     info("Client Transport is built.");
     clientTransport = aTransport;
     clientTransport.callback = clientCallback;
   },
   onError: function(aError)  {
     ok(false, "client's builder reports error " + aError);
   },
@@ -116,17 +116,17 @@ const clientListener = {
     this._remoteBuilder = aRemoteBuilder;
   },
   set localBuilder(aLocalBuilder) {
     this._localBuilder = aLocalBuilder;
   },
 }
 
 const serverListener = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
   onSessionTransport: function(aTransport) {
     info("Server Transport is built.");
     serverTransport = aTransport;
     serverTransport.callback = serverCallback;
     serverTransport.enableDataNotification();
   },
   onError: function(aError)  {
     ok(false, "server's builder reports error " + aError);
--- a/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js
+++ b/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js
@@ -59,17 +59,17 @@ MockFactory.prototype = {
         return this._cls.QueryInterface(aIID);
       default:
         return null;
     }
   },
   lockFactory: function(aLock) {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIFactory])
 };
 
 function ContractHook(aContractID, aClass) {
   this._contractID = aContractID;
   this.classID = Cc[UUID_CONTRACT_ID].getService(Ci.nsIUUIDGenerator).generateUUID();
   this._newFactory = new MockFactory(aClass);
 
   if (!this.hookedMap.has(this._contractID)) {
@@ -127,17 +127,17 @@ ContractHook.prototype = {
     }
 
     return { classID: classID, factory: factory };
   }
 };
 
 function MockDNSServiceInfo() {}
 MockDNSServiceInfo.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceInfo]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceInfo]),
 
   set host(aHost) {
     this._host = aHost;
   },
 
   get host() {
     return this._host;
   },
@@ -190,18 +190,18 @@ MockDNSServiceInfo.prototype = {
     return this._attributes;
   }
 };
 
 function TestPresentationDeviceListener() {
   this.devices = {};
 }
 TestPresentationDeviceListener.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                          Ci.nsISupportsWeakReference]),
 
   addDevice: function(device) { this.devices[device.id] = device; },
   removeDevice: function(device) { delete this.devices[device.id]; },
   updateDevice: function(device) { this.devices[device.id] = device; },
   onSessionRequest: function(device, url, presentationId, controlChannel) {},
 
   count: function() {
     var size = 0, key;
@@ -227,23 +227,23 @@ function createDevice(host, port, servic
 }
 
 function registerService() {
   Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
 
   let deferred = Promise.defer();
 
   let mockObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {},
     registerService: function(serviceInfo, listener) {
       deferred.resolve();
       this.serviceRegistered++;
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: () => {
           this.serviceUnregistered++;
         }
       };
     },
     resolveService: function(serviceInfo, listener) {},
     serviceRegistered: 0,
     serviceUnregistered: 0
@@ -251,18 +251,18 @@ function registerService() {
   let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
 
   Assert.equal(mockObj.serviceRegistered, 0);
   Assert.equal(mockObj.serviceUnregistered, 0);
 
   // Register
   provider.listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) {},
     removeDevice: function(device) {},
     updateDevice: function(device) {},
   };
 
   deferred.promise.then(function() {
     Assert.equal(mockObj.serviceRegistered, 1);
     Assert.equal(mockObj.serviceUnregistered, 0);
@@ -277,32 +277,32 @@ function registerService() {
 }
 
 function noRegisterService() {
   Services.prefs.setBoolPref(PREF_DISCOVERABLE, false);
 
   let deferred = Promise.defer();
 
   let mockObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {},
     registerService: function(serviceInfo, listener) {
       deferred.resolve();
       Assert.ok(false, "should not register service if not discoverable");
     },
     resolveService: function(serviceInfo, listener) {},
   };
 
   let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
 
   // Try register
   provider.listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) {},
     removeDevice: function(device) {},
     updateDevice: function(device) {},
   };
 
   let race = Promise.race([
     deferred.promise,
     sleep(1000),
@@ -316,23 +316,23 @@ function noRegisterService() {
 }
 
 function registerServiceDynamically() {
   Services.prefs.setBoolPref(PREF_DISCOVERABLE, false);
 
   let deferred = Promise.defer();
 
   let mockObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {},
     registerService: function(serviceInfo, listener) {
       deferred.resolve();
       this.serviceRegistered++;
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: () => {
           this.serviceUnregistered++;
         }
       };
     },
     resolveService: function(serviceInfo, listener) {},
     serviceRegistered: 0,
     serviceUnregistered: 0
@@ -340,18 +340,18 @@ function registerServiceDynamically() {
   let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
 
   Assert.equal(mockObj.serviceRegistered, 0);
   Assert.equal(mockObj.serviceRegistered, 0);
 
   // Try Register
   provider.listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) {},
     removeDevice: function(device) {},
     updateDevice: function(device) {},
   };
 
   Assert.equal(mockObj.serviceRegistered, 0);
   Assert.equal(mockObj.serviceUnregistered, 0);
 
@@ -379,25 +379,25 @@ function registerServiceDynamically() {
 function addDevice() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, true);
 
   let mockDevice = createDevice("device.local",
                                 12345,
                                 "service.name",
                                 SERVICE_TYPE);
   let mockObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
       listener.onServiceFound(createDevice("",
                                            0,
                                            mockDevice.serviceName,
                                            mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     registerService: function(serviceInfo, listener) {},
     resolveService: function(serviceInfo, listener) {
       Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
       Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
       listener.onServiceResolved(createDevice(mockDevice.host,
@@ -429,25 +429,25 @@ function addDevice() {
 function filterDevice() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, true);
 
   let mockDevice = createDevice("device.local",
                                 12345,
                                 "service.name",
                                 SERVICE_TYPE);
   let mockObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
       listener.onServiceFound(createDevice("",
                                            0,
                                            mockDevice.serviceName,
                                            mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     registerService: function(serviceInfo, listener) {},
     resolveService: function(serviceInfo, listener) {
       Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
       Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
       listener.onServiceResolved(createDevice(mockDevice.host,
@@ -455,18 +455,18 @@ function filterDevice() {
                                               mockDevice.serviceName,
                                               mockDevice.serviceType));
     }
   };
 
   let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
   let listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) {
       let tests = [
         { requestedUrl: "app://fling-player.gaiamobile.org/index.html", supported: true },
         { requestedUrl: "app://notification-receiver.gaiamobile.org/index.html", supported: true },
         { requestedUrl: "http://example.com", supported: true },
         { requestedUrl: "https://example.com", supported: true },
         { requestedUrl: "ftp://example.com", supported: false },
         { requestedUrl: "app://unknown-app-id", supported: false },
@@ -499,60 +499,60 @@ function handleSessionRequest() {
 
   Services.prefs.setCharPref(PREF_DEVICENAME, testDeviceName);
 
   let mockDevice = createDevice("device.local",
                                 12345,
                                 "service.name",
                                 SERVICE_TYPE);
   let mockSDObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
       listener.onServiceFound(createDevice("",
                                            0,
                                            mockDevice.serviceName,
                                            mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     registerService: function(serviceInfo, listener) {},
     resolveService: function(serviceInfo, listener) {
       listener.onServiceResolved(createDevice(mockDevice.host,
                                               mockDevice.port,
                                               mockDevice.serviceName,
                                               mockDevice.serviceType));
     }
   };
 
   let mockServerObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlService]),
     connect: function(deviceInfo) {
       this.request = {
         deviceInfo: deviceInfo,
       };
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel]),
       };
     },
     id: "",
     version: LATEST_VERSION,
     isCompatibleServer: function(version) {
       return this.version === version;
     }
   };
 
   let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
   let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
   let listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) {
       this.device = device;
     },
   };
 
   provider.listener = listener;
 
   let controlChannel = listener.device.establishControlChannel();
@@ -571,80 +571,80 @@ function handleOnSessionRequest() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, true);
   Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
 
   let mockDevice = createDevice("device.local",
                                 12345,
                                 "service.name",
                                 SERVICE_TYPE);
   let mockSDObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
       listener.onServiceFound(createDevice("",
                                            0,
                                            mockDevice.serviceName,
                                            mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     registerService: function(serviceInfo, listener) {},
     resolveService: function(serviceInfo, listener) {
       listener.onServiceResolved(createDevice(mockDevice.host,
                                               mockDevice.port,
                                               mockDevice.serviceName,
                                               mockDevice.serviceType));
     }
   };
 
   let mockServerObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlService]),
     startServer: function() {},
     sessionRequest: function() {},
     close: function() {},
     id: '',
     version: LATEST_VERSION,
     port: 0,
     listener: null,
   };
 
   let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
   let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
   let listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) {},
     removeDevice: function(device) {},
     updateDevice: function(device) {},
     onSessionRequest: function(device, url, presentationId, controlChannel) {
       Assert.ok(true, "receive onSessionRequest event");
       this.request = {
         deviceId: device.id,
         url: url,
         presentationId: presentationId,
       };
     }
   };
 
   provider.listener = listener;
 
   const deviceInfo = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsITCPDeviceInfo]),
     id: mockDevice.host,
     address: mockDevice.host,
     port: 54321,
   };
 
   const testUrl = "http://example.com";
   const testPresentationId = "test-presentation-id";
   const testControlChannel = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel]),
   };
   provider.QueryInterface(Ci.nsIPresentationControlServerListener)
           .onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel);
 
   Assert.equal(listener.request.deviceId, deviceInfo.id);
   Assert.equal(listener.request.url, testUrl);
   Assert.equal(listener.request.presentationId, testPresentationId);
 
@@ -653,39 +653,39 @@ function handleOnSessionRequest() {
   run_next_test();
 }
 
 function handleOnSessionRequestFromUnknownDevice() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, false);
   Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
 
   let mockSDObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {},
     registerService: function(serviceInfo, listener) {},
     resolveService: function(serviceInfo, listener) {}
   };
 
   let mockServerObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlService]),
     startServer: function() {},
     sessionRequest: function() {},
     close: function() {},
     id: '',
     version: LATEST_VERSION,
     port: 0,
     listener: null,
   };
 
   let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
   let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
   let listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) {
       Assert.ok(false, "shouldn't create any new device");
     },
     removeDevice: function(device) {
       Assert.ok(false, "shouldn't remote any device");
     },
     updateDevice: function(device) {
       Assert.ok(false, "shouldn't update any device");
@@ -698,26 +698,26 @@ function handleOnSessionRequestFromUnkno
         presentationId: presentationId,
       };
     }
   };
 
   provider.listener = listener;
 
   const deviceInfo = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsITCPDeviceInfo]),
     id: "unknown-device.local",
     address: "unknown-device.local",
     port: 12345,
   };
 
   const testUrl = "http://example.com";
   const testPresentationId = "test-presentation-id";
   const testControlChannel = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel]),
   };
   provider.QueryInterface(Ci.nsIPresentationControlServerListener)
           .onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel);
 
   Assert.equal(listener.request.deviceId, deviceInfo.id);
   Assert.equal(listener.request.url, testUrl);
   Assert.equal(listener.request.presentationId, testPresentationId);
 
@@ -726,30 +726,30 @@ function handleOnSessionRequestFromUnkno
   run_next_test();
 }
 
 function noAddDevice() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, false);
 
   let mockDevice = createDevice("device.local", 12345, "service.name", SERVICE_TYPE);
   let mockObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       Assert.ok(false, "shouldn't perform any device discovery");
     },
     registerService: function(serviceInfo, listener) {},
     resolveService: function(serviceInfo, listener) {
     }
   };
   let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
 
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
   let listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) {},
     removeDevice: function(device) {},
     updateDevice: function(device) {},
   };
   provider.listener = listener;
   provider.forceDiscovery();
   provider.listener = null;
 
@@ -763,51 +763,51 @@ function ignoreIncompatibleDevice() {
   let mockDevice = createDevice("device.local",
                                 12345,
                                 "service.name",
                                 SERVICE_TYPE);
 
   let deferred = Promise.defer();
 
   let mockSDObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
       listener.onServiceFound(createDevice("",
                                            0,
                                            mockDevice.serviceName,
                                            mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     registerService: function(serviceInfo, listener) {
       deferred.resolve();
       listener.onServiceRegistered(createDevice("",
                                                 54321,
                                                 mockDevice.serviceName,
                                                 mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     resolveService: function(serviceInfo, listener) {
       Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
       Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
       listener.onServiceResolved(createDevice(mockDevice.host,
                                               mockDevice.port,
                                               mockDevice.serviceName,
                                               mockDevice.serviceType));
     }
   };
 
   let mockServerObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlService]),
     startServer: function() {
       Services.tm.dispatchToMainThread(() => {
         this.listener.onServerReady(this.port, this.certFingerprint);
       });
     },
     sessionRequest: function() {},
     close: function() {},
     id: '',
@@ -848,51 +848,51 @@ function ignoreSelfDevice() {
 
   let mockDevice = createDevice("device.local",
                                 12345,
                                 "service.name",
                                 SERVICE_TYPE);
 
   let deferred = Promise.defer();
   let mockSDObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
       listener.onServiceFound(createDevice("",
                                            0,
                                            mockDevice.serviceName,
                                            mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     registerService: function(serviceInfo, listener) {
       deferred.resolve();
       listener.onServiceRegistered(createDevice("",
                                                 0,
                                                 mockDevice.serviceName,
                                                 mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     resolveService: function(serviceInfo, listener) {
       Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
       Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
       listener.onServiceResolved(createDevice(mockDevice.host,
                                               mockDevice.port,
                                               mockDevice.serviceName,
                                               mockDevice.serviceType));
     }
   };
 
   let mockServerObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlService]),
     startServer: function() {
       Services.tm.dispatchToMainThread(() => {
         this.listener.onServerReady(this.port, this.certFingerprint);
       });
     },
     sessionRequest: function() {},
     close: function() {},
     id: '',
@@ -929,25 +929,25 @@ function ignoreSelfDevice() {
 function addDeviceDynamically() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, false);
 
   let mockDevice = createDevice("device.local",
                                 12345,
                                 "service.name",
                                 SERVICE_TYPE);
   let mockObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
       listener.onServiceFound(createDevice("",
                                            0,
                                            mockDevice.serviceName,
                                            mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     registerService: function(serviceInfo, listener) {},
     resolveService: function(serviceInfo, listener) {
       Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
       Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
       listener.onServiceResolved(createDevice(mockDevice.host,
@@ -986,29 +986,29 @@ function updateDevice() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, true);
 
   let mockDevice1 = createDevice("A.local", 12345, "N1", SERVICE_TYPE);
   let mockDevice2 = createDevice("A.local", 23456, "N2", SERVICE_TYPE);
 
   let mockObj = {
     discovered: false,
 
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
 
       if (!this.discovered) {
         listener.onServiceFound(mockDevice1);
       } else {
         listener.onServiceFound(mockDevice2);
       }
       this.discovered = true;
 
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {
           listener.onDiscoveryStopped(serviceType);
         }
       };
     },
     registerService: function(serviceInfo, listener) {},
     resolveService: function(serviceInfo, listener) {
       Assert.equal(serviceInfo.serviceType, SERVICE_TYPE);
@@ -1020,18 +1020,18 @@ function updateDevice() {
         Assert.ok(false);
       }
     }
   };
 
   let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
   let listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
 
     addDevice: function(device) {
       Assert.ok(!this.isDeviceAdded);
       Assert.equal(device.id, mockDevice1.host);
       Assert.equal(device.name, mockDevice1.serviceName);
       this.isDeviceAdded = true;
     },
     removeDevice: function(device) { Assert.ok(false); },
@@ -1073,31 +1073,31 @@ function diffDiscovery() {
 
   let mockDevice1 = createDevice("A.local", 12345, "N1", SERVICE_TYPE);
   let mockDevice2 = createDevice("B.local", 23456, "N2", SERVICE_TYPE);
   let mockDevice3 = createDevice("C.local", 45678, "N3", SERVICE_TYPE);
 
   let mockObj = {
     discovered: false,
 
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
 
       if (!this.discovered) {
         listener.onServiceFound(mockDevice1);
         listener.onServiceFound(mockDevice2);
       } else {
         listener.onServiceFound(mockDevice1);
         listener.onServiceFound(mockDevice3);
       }
       this.discovered = true;
 
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {
           listener.onDiscoveryStopped(serviceType);
         }
       };
     },
     registerService: function(serviceInfo, listener) {},
     resolveService: function(serviceInfo, listener) {
       Assert.equal(serviceInfo.serviceType, SERVICE_TYPE);
@@ -1155,32 +1155,32 @@ function serverClosed() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, true);
 
   let mockDevice = createDevice("device.local",
                                 12345,
                                 "service.name",
                                 SERVICE_TYPE);
 
   let mockObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {
       listener.onDiscoveryStarted(serviceType);
       listener.onServiceFound(createDevice("",
                                            0,
                                            mockDevice.serviceName,
                                            mockDevice.serviceType));
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: function() {}
       };
     },
     registerService: function(serviceInfo, listener) {
       this.serviceRegistered++;
       return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsICancelable]),
         cancel: () => {
           this.serviceUnregistered++;
         }
       };
     },
     resolveService: function(serviceInfo, listener) {
       Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
       Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
@@ -1195,18 +1195,18 @@ function serverClosed() {
   let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
 
   Assert.equal(mockObj.serviceRegistered, 0);
   Assert.equal(mockObj.serviceUnregistered, 0);
 
   // Register
   let listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) { this.devices.push(device); },
     removeDevice: function(device) {},
     updateDevice: function(device) {},
     devices: []
   };
   Assert.equal(listener.devices.length, 0);
 
   provider.listener = listener;
@@ -1233,28 +1233,28 @@ function serverClosed() {
 
 function serverRetry() {
   Services.prefs.setBoolPref(PREF_DISCOVERY, false);
   Services.prefs.setBoolPref(PREF_DISCOVERABLE, true);
 
   let isRetrying = false;
 
   let mockSDObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
     startDiscovery: function(serviceType, listener) {},
     registerService: function(serviceInfo, listener) {
       Assert.ok(isRetrying, "register service after retrying startServer");
       provider.listener = null;
       run_next_test();
     },
     resolveService: function(serviceInfo, listener) {}
   };
 
   let mockServerObj = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlService]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlService]),
     startServer: function(encrypted, port) {
       if (!isRetrying) {
         isRetrying = true;
         Services.tm.dispatchToMainThread(() => {
           this.listener.onServerStopped(Cr.NS_ERROR_FAILURE);
         });
       } else {
         this.port = 54321;
@@ -1271,18 +1271,18 @@ function serverRetry() {
     certFingerprint: 'mock-cert-fingerprint',
     listener: null,
   };
 
   let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj);
   let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj);
   let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
   let listener = {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
-                                           Ci.nsISupportsWeakReference]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceListener,
+                                            Ci.nsISupportsWeakReference]),
     addDevice: function(device) {},
     removeDevice: function(device) {},
     updateDevice: function(device) {},
     onSessionRequest: function(device, url, presentationId, controlChannel) {}
   };
 
   provider.listener = listener;
 }
--- a/dom/presentation/tests/xpcshell/test_presentation_device_manager.js
+++ b/dom/presentation/tests/xpcshell/test_presentation_device_manager.js
@@ -11,41 +11,41 @@ const manager = Cc['@mozilla.org/present
                   .getService(Ci.nsIPresentationDeviceManager);
 
 function TestPresentationDevice() {}
 
 
 function TestPresentationControlChannel() {}
 
 TestPresentationControlChannel.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel]),
   sendOffer: function(offer) {},
   sendAnswer: function(answer) {},
   disconnect: function() {},
   launch: function() {},
   terminate: function() {},
   reconnect: function() {},
   set listener(listener) {},
   get listener() {},
 };
 
 var testProvider = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceProvider]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDeviceProvider]),
 
   forceDiscovery: function() {
   },
   set listener(listener) {
   },
   get listener() {
   },
 };
 
 const forbiddenRequestedUrl = 'http://example.com';
 var testDevice = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationDevice]),
   id: 'id',
   name: 'name',
   type: 'type',
   establishControlChannel: function(url, presentationId) {
     return null;
   },
   disconnect: function() {},
   isRequestedUrlSupported: function(requestedUrl) {
--- a/dom/presentation/tests/xpcshell/test_presentation_session_transport.js
+++ b/dom/presentation/tests/xpcshell/test_presentation_session_transport.js
@@ -24,28 +24,28 @@ const serverMessage = "Server Message";
 
 const address = Cc["@mozilla.org/supports-cstring;1"]
                   .createInstance(Ci.nsISupportsCString);
 address.data = "127.0.0.1";
 const addresses = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
 addresses.appendElement(address);
 
 const serverChannelDescription = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationChannelDescription]),
   type: 1,
   tcpAddress: addresses,
 };
 
 var isClientReady = false;
 var isServerReady = false;
 var isClientClosed = false;
 var isServerClosed = false;
 
 const clientCallback = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
   notifyTransportReady: function () {
     Assert.ok(true, "Client transport ready.");
 
     isClientReady = true;
     if (isClientReady && isServerReady) {
       run_next_test();
     }
   },
@@ -59,17 +59,17 @@ const clientCallback = {
   },
   notifyData: function(aData) {
     Assert.equal(aData, serverMessage, "Client transport receives data.");
     run_next_test();
   },
 };
 
 const serverCallback = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransportCallback]),
   notifyTransportReady: function () {
     Assert.ok(true, "Server transport ready.");
 
     isServerReady = true;
     if (isClientReady && isServerReady) {
       run_next_test();
     }
   },
@@ -83,30 +83,30 @@ const serverCallback = {
   },
   notifyData: function(aData) {
     Assert.equal(aData, clientMessage, "Server transport receives data.");
     run_next_test();
   },
 };
 
 const clientListener = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
   onSessionTransport(aTransport) {
     Assert.ok(true, "Client Transport is built.");
     clientTransport = aTransport;
     clientTransport.callback = clientCallback;
 
     if (serverTransport) {
       run_next_test();
     }
   }
 }
 
 const serverListener = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationSessionTransportBuilderListener]),
   onSessionTransport(aTransport) {
     Assert.ok(true, "Server Transport is built.");
     serverTransport = aTransport;
     serverTransport.callback = serverCallback;
     serverTransport.enableDataNotification();
 
     if (clientTransport) {
       run_next_test();
--- a/dom/presentation/tests/xpcshell/test_tcp_control_channel.js
+++ b/dom/presentation/tests/xpcshell/test_tcp_control_channel.js
@@ -31,17 +31,17 @@ function TestDescription(aType, aTcpAddr
                     .createInstance(Ci.nsISupportsCString);
     wrapper.data = address;
     this.tcpAddress.appendElement(wrapper);
   }
   this.tcpPort = aTcpPort;
 }
 
 TestDescription.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationChannelDescription]),
 }
 
 const CONTROLLER_CONTROL_CHANNEL_PORT = 36777;
 const PRESENTER_CONTROL_CHANNEL_PORT = 36888;
 
 var CLOSE_CONTROL_CHANNEL_REASON = Cr.NS_OK;
 var candidate;
 
@@ -121,34 +121,34 @@ function testPresentationServer() {
           this.status = 'opened';
         },
         notifyDisconnected: function(aReason) {
           Assert.equal(this.status, 'onOffer', '4. presenterControlChannel: closed');
           Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, 'presenterControlChannel notify closed');
           this.status = 'closed';
           yayFuncs.controllerControlChannelClose();
         },
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
       };
     },
     onReconnectRequest: function(deviceInfo, url, presentationId, controlChannel) {
       Assert.equal(url, 'http://example.com', 'expected url');
       Assert.equal(presentationId, 'testPresentationId', 'expected presentation id');
       yayFuncs.presenterControlChannelReconnect();
     },
 
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlServerListener]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlServerListener]),
   };
 
   let presenterDeviceInfo = {
     id: 'presentatorID',
     address: '127.0.0.1',
     port: PRESENTER_CONTROL_CHANNEL_PORT,
     certFingerprint: pcs.certFingerprint,
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsITCPDeviceInfo]),
   };
 
   let controllerControlChannel = pcs.connect(presenterDeviceInfo);
 
   controllerControlChannel.listener = {
     status: 'created',
     onOffer: function(offer) {
       Assert.ok(false, 'get offer');
@@ -191,20 +191,20 @@ function testPresentationServer() {
       let reconnectControllerControlChannel = pcs.connect(presenterDeviceInfo);
       reconnectControllerControlChannel.listener = {
         notifyConnected: function() {
           reconnectControllerControlChannel.reconnect('testPresentationId', 'http://example.com');
         },
         notifyReconnected: function() {
           yayFuncs.controllerControlChannelReconnect();
         },
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
       };
     },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
   };
 }
 
 function terminateRequest() {
   let yayFuncs = makeJointSuccess(['controllerControlChannelConnected',
                                    'controllerControlChannelDisconnected',
                                    'presenterControlChannelDisconnected',
                                    'terminatedByController',
@@ -231,47 +231,47 @@ function terminateRequest() {
 
             terminatePhase = 'receiver';
             controllerControlChannel.terminate('testPresentationId');
           },
           notifyDisconnected: function(aReason) {
             Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, 'controllerControlChannel notify disconncted');
             yayFuncs.controllerControlChannelDisconnected();
           },
-          QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
+          QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
         };
       } else {
         Assert.equal(deviceInfo.id, presenterDeviceInfo.id, 'expected presenter device id');
         Assert.equal(isFromReceiver, true, 'expected request from receiver');
         yayFuncs.terminatedByReceiver();
         presenterControlChannel.disconnect(CLOSE_CONTROL_CHANNEL_REASON);
       }
     },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServerListener]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsITCPPresentationServerListener]),
   };
 
   let presenterDeviceInfo = {
     id: 'presentatorID',
     address: '127.0.0.1',
     port: PRESENTER_CONTROL_CHANNEL_PORT,
     certFingerprint: pcs.certFingerprint,
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsITCPDeviceInfo]),
   };
 
   let presenterControlChannel = pcs.connect(presenterDeviceInfo);
 
   presenterControlChannel.listener = {
     notifyConnected: function() {
       presenterControlChannel.terminate('testPresentationId');
     },
     notifyDisconnected: function(aReason) {
       Assert.equal(aReason, CLOSE_CONTROL_CHANNEL_REASON, '4. presenterControlChannel notify disconnected');
       yayFuncs.presenterControlChannelDisconnected();
     },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
   };
 }
 
 function terminateRequestAbnormal() {
   let yayFuncs = makeJointSuccess(['controllerControlChannelConnected',
                                    'controllerControlChannelDisconnected',
                                    'presenterControlChannelDisconnected']);
   let controllerControlChannel;
@@ -290,41 +290,41 @@ function terminateRequestAbnormal() {
           notifyConnected: function() {
           Assert.ok(true, 'control channel notify connected');
           yayFuncs.controllerControlChannelConnected();
         },
         notifyDisconnected: function(aReason) {
           Assert.equal(aReason, Cr.NS_ERROR_FAILURE, 'controllerControlChannel notify disconncted with error');
           yayFuncs.controllerControlChannelDisconnected();
         },
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
       };
     },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServerListener]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsITCPPresentationServerListener]),
   };
 
   let presenterDeviceInfo = {
     id: 'presentatorID',
     address: '127.0.0.1',
     port: PRESENTER_CONTROL_CHANNEL_PORT,
     certFingerprint: pcs.certFingerprint,
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsITCPDeviceInfo]),
   };
 
   let presenterControlChannel = pcs.connect(presenterDeviceInfo);
 
   presenterControlChannel.listener = {
     notifyConnected: function() {
       presenterControlChannel.terminate('testPresentationId');
     },
     notifyDisconnected: function(aReason) {
       Assert.equal(aReason, Cr.NS_ERROR_FAILURE, '4. presenterControlChannel notify disconnected with error');
       yayFuncs.presenterControlChannelDisconnected();
     },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannelListener]),
   };
 }
 
 function setOffline() {
   pcs.listener = {
     onServerReady: function(aPort, aCertFingerprint) {
       Assert.notEqual(aPort, 0, 'TCPPresentationServer port changed and the port should be valid');
       pcs.close();
--- a/dom/push/Push.js
+++ b/dom/push/Push.js
@@ -32,19 +32,19 @@ function Push() {
 
 Push.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   contractID: "@mozilla.org/push/PushManager;1",
 
   classID : PUSH_CID,
 
-  QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
-                                          Ci.nsISupportsWeakReference,
-                                          Ci.nsIObserver]),
+  QueryInterface : ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
+                                           Ci.nsISupportsWeakReference,
+                                           Ci.nsIObserver]),
 
   init: function(win) {
     console.debug("init()");
 
     this._window = win;
 
     this.initDOMRequestHelper(win);
 
@@ -177,26 +177,26 @@ Push.prototype = {
   },
 
   _requestPermission: function(allowCallback, cancelCallback) {
     // Create an array with a single nsIContentPermissionType element.
     let type = {
       type: "desktop-notification",
       access: null,
       options: [],
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType]),
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionType]),
     };
     let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
     typeArray.appendElement(type);
 
     // create a nsIContentPermissionRequest
     let request = {
       types: typeArray,
       principal: this._principal,
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
+      QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionRequest]),
       allow: allowCallback,
       cancel: cancelCallback,
       window: this._window,
     };
 
     // Using askPermission from nsIDOMWindowUtils that takes care of the
     // remoting if needed.
     let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -207,17 +207,17 @@ Push.prototype = {
 
 function PushSubscriptionCallback(pushManager, resolve, reject) {
   this.pushManager = pushManager;
   this.resolve = resolve;
   this.reject = reject;
 }
 
 PushSubscriptionCallback.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPushSubscriptionCallback]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPushSubscriptionCallback]),
 
   onPushSubscription: function(ok, subscription) {
     let {pushManager} = this;
     if (!Components.isSuccessCode(ok)) {
       this._rejectWithError(ok);
       return;
     }
 
--- a/dom/push/PushComponents.js
+++ b/dom/push/PushComponents.js
@@ -44,17 +44,17 @@ const OBSERVER_TOPIC_SUBSCRIPTION_MODIFI
 function PushServiceBase() {
   this.wrappedJSObject = this;
   this._addListeners();
 }
 
 PushServiceBase.prototype = {
   classID: Components.ID("{daaa8d73-677e-4233-8acd-2c404bd01658}"),
   contractID: "@mozilla.org/push/Service;1",
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference,
     Ci.nsIPushService,
     Ci.nsIPushQuotaManager,
     Ci.nsIPushErrorReporter,
   ]),
 
   pushTopic: OBSERVER_TOPIC_PUSH,
@@ -454,17 +454,17 @@ Object.assign(PushServiceContent.prototy
 });
 
 /** `PushSubscription` instances are passed to all subscription callbacks. */
 function PushSubscription(props) {
   this._props = props;
 }
 
 PushSubscription.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPushSubscription]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIPushSubscription]),
 
   /** The URL for sending messages to this subscription. */
   get endpoint() {
     return this._props.endpoint;
   },
 
   /** The last time a message was sent to this subscription. */
   get lastPush() {
--- a/dom/push/PushServiceHttp2.jsm
+++ b/dom/push/PushServiceHttp2.jsm
@@ -45,23 +45,18 @@ const kPUSHHTTP2DB_STORE_NAME = "pushHtt
 var PushSubscriptionListener = function(pushService, uri) {
   console.debug("PushSubscriptionListener()");
   this._pushService = pushService;
   this.uri = uri;
 };
 
 PushSubscriptionListener.prototype = {
 
-  QueryInterface: function (aIID) {
-    if (aIID.equals(Ci.nsIHttpPushListener) ||
-        aIID.equals(Ci.nsIStreamListener)) {
-      return this;
-    }
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIHttpPushListener",
+                                         "nsIStreamListener"]),
 
   getInterface: function(aIID) {
     return this.QueryInterface(aIID);
   },
 
   onStartRequest: function(aRequest, aContext) {
     console.debug("PushSubscriptionListener: onStartRequest()");
     // We do not do anything here.
--- a/dom/push/test/mockpushserviceparent.js
+++ b/dom/push/test/mockpushserviceparent.js
@@ -25,20 +25,17 @@ function MockWebSocketParent(originalURI
 }
 
 MockWebSocketParent.prototype = {
   _originalURI: null,
 
   _listener: null,
   _context: null,
 
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsISupports,
-    Ci.nsIWebSocketChannel
-  ]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebSocketChannel]),
 
   get originalURI() {
     return this._originalURI;
   },
 
   asyncOpen(uri, origin, windowId, listener, context) {
     this._listener = listener;
     this._context = context;
--- a/dom/push/test/xpcshell/PushServiceHandler.js
+++ b/dom/push/test/xpcshell/PushServiceHandler.js
@@ -14,16 +14,16 @@ function PushServiceHandler() {
   this.observed = [];
   Services.obs.addObserver(this, pushService.pushTopic);
   Services.obs.addObserver(this, pushService.subscriptionChangeTopic);
   Services.obs.addObserver(this, pushService.subscriptionModifiedTopic);
 }
 
 PushServiceHandler.prototype = {
   classID: Components.ID("{bb7c5199-c0f7-4976-9f6d-1306e32c5591}"),
-  QueryInterface: XPCOMUtils.generateQI([]),
+  QueryInterface: ChromeUtils.generateQI([]),
 
   observe(subject, topic, data) {
     this.observed.push({ subject, topic, data });
   },
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PushServiceHandler]);
--- a/dom/push/test/xpcshell/head.js
+++ b/dom/push/test/xpcshell/head.js
@@ -193,20 +193,17 @@ MockWebSocket.prototype = {
   _onRegister: null,
   _onUnregister: null,
   _onACK: null,
   _onPing: null,
 
   _listener: null,
   _context: null,
 
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsISupports,
-    Ci.nsIWebSocketChannel
-  ]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebSocketChannel]),
 
   get originalURI() {
     return this._originalURI;
   },
 
   asyncOpen(uri, origin, windowId, listener, context) {
     this._listener = listener;
     this._context = context;
--- a/dom/push/test/xpcshell/test_permissions.js
+++ b/dom/push/test/xpcshell/test_permissions.js
@@ -24,17 +24,17 @@ function run_test() {
 let unregisterDefers = {};
 
 function promiseUnregister(keyID) {
   return new Promise(r => unregisterDefers[keyID] = r);
 }
 
 function makePushPermission(url, capability) {
   return {
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIPermission]),
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIPermission]),
     capability: Ci.nsIPermissionManager[capability],
     expireTime: 0,
     expireType: Ci.nsIPermissionManager.EXPIRE_NEVER,
     principal: Services.scriptSecurityManager.createCodebasePrincipal(
       Services.io.newURI(url), {}
     ),
     type: 'desktop-notification',
   };
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.js
@@ -206,27 +206,27 @@ function WifiGeoCoordsObject(lat, lon, a
   this.latitude = lat;
   this.longitude = lon;
   this.accuracy = acc;
   this.altitude = alt;
   this.altitudeAccuracy = altacc;
 }
 
 WifiGeoCoordsObject.prototype = {
-  QueryInterface:  XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionCoords])
+  QueryInterface:  ChromeUtils.generateQI([Ci.nsIDOMGeoPositionCoords])
 };
 
 function WifiGeoPositionObject(lat, lng, acc) {
   this.coords = new WifiGeoCoordsObject(lat, lng, acc, 0, 0);
   this.address = null;
   this.timestamp = Date.now();
 }
 
 WifiGeoPositionObject.prototype = {
-  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIDOMGeoPosition])
+  QueryInterface:   ChromeUtils.generateQI([Ci.nsIDOMGeoPosition])
 };
 
 function WifiGeoPositionProvider() {
   try {
     gLoggingEnabled = Services.prefs.getBoolPref("geo.wifi.logging.enabled");
   } catch (e) {}
 
   try {
@@ -239,20 +239,20 @@ function WifiGeoPositionProvider() {
 
   this.wifiService = null;
   this.timer = null;
   this.started = false;
 }
 
 WifiGeoPositionProvider.prototype = {
   classID:          Components.ID("{77DA64D3-7458-4920-9491-86CC9914F904}"),
-  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIGeolocationProvider,
-                                           Ci.nsIWifiListener,
-                                           Ci.nsITimerCallback,
-                                           Ci.nsIObserver]),
+  QueryInterface:   ChromeUtils.generateQI([Ci.nsIGeolocationProvider,
+                                            Ci.nsIWifiListener,
+                                            Ci.nsITimerCallback,
+                                            Ci.nsIObserver]),
   listener: null,
 
   resetTimer: function() {
     if (this.timer) {
       this.timer.cancel();
       this.timer = null;
     }
     // wifi thread triggers WifiGeoPositionProvider to proceed, with no wifi, do manual timeout
--- a/dom/tests/browser/browser_ConsoleAPI_originAttributes.js
+++ b/dom/tests/browser/browser_ConsoleAPI_originAttributes.js
@@ -5,17 +5,17 @@ const ConsoleAPIStorage = Cc["@mozilla.o
       .getService(Ci.nsIConsoleAPIStorage);
 
 const {WebExtensionPolicy} = Cu.getGlobalForObject(ChromeUtils.import("resource://gre/modules/Services.jsm", {}));
 
 const FAKE_ADDON_ID = "test-webext-addon@mozilla.org";
 const EXPECTED_CONSOLE_ID = `addon/${FAKE_ADDON_ID}`;
 const EXPECTED_CONSOLE_MESSAGE_CONTENT = "fake-webext-addon-test-log-message";
 const ConsoleObserver = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
   init() {
     Services.obs.addObserver(this, "console-api-log-event");
   },
 
   uninit() {
     Services.obs.removeObserver(this, "console-api-log-event");
   },
--- a/dom/tests/browser/browser_ConsoleStorageAPITests.js
+++ b/dom/tests/browser/browser_ConsoleStorageAPITests.js
@@ -28,17 +28,17 @@ add_task(async function()
   let observerPromise = ContentTask.spawn(browser, null, async function(opt) {
     const TEST_URI = "http://example.com/browser/dom/tests/browser/test-console-api.html";
     let ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"]
           .getService(Ci.nsIConsoleAPIStorage);
 
     let observerPromise = new Promise(resolve => {
       let apiCallCount = 0;
       let ConsoleObserver = {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+        QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
         observe: function(aSubject, aTopic, aData) {
           if (aTopic == "console-storage-cache-event") {
             apiCallCount++;
             if (apiCallCount == 4) {
               let windowId = content.window.QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
 
--- a/dom/tests/browser/browser_bug1004814.js
+++ b/dom/tests/browser/browser_bug1004814.js
@@ -5,17 +5,17 @@
 
 add_task(async function() {
   await BrowserTestUtils.withNewTab("about:blank", async function(aBrowser) {
     let duration = await ContentTask.spawn(aBrowser, null, function (opts) {
       const TEST_URI = "http://example.com/browser/dom/tests/browser/test_bug1004814.html";
 
       return new Promise(resolve => {
         let ConsoleObserver = {
-          QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+          QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
           observe: function(aSubject, aTopic, aData) {
             var obj = aSubject.wrappedJSObject;
             if (obj.arguments.length != 1 || obj.arguments[0] != 'bug1004814' ||
                 obj.level != 'timeEnd') {
               return;
             }
 
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -784,18 +784,16 @@ var interfaceNamesInGlobalScope =
     {name: "PluginArray", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PointerEvent", insecureContext: true, android: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PopStateEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PopupBlockedEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "PopupBoxObject", insecureContext: true, xbl: true},
-// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Presentation", insecureContext: true, desktop: false, release: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PresentationAvailability", insecureContext: true, desktop: false, release: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PresentationConnection", insecureContext: true, desktop: false, release: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PresentationConnectionAvailableEvent", insecureContext: true, desktop: false, release: false },
 // IMPORTANT: Do not change this list without review from a DOM peer!
@@ -1264,16 +1262,18 @@ var interfaceNamesInGlobalScope =
     {name: "XSLTProcessor", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "XULCommandEvent", insecureContext: true, xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "XULDocument", insecureContext: true, xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "XULElement", insecureContext: true, xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "XULPopupElement", insecureContext: true, xbl: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
   ];
 // IMPORTANT: Do not change the list above without review from a DOM peer!
 
 function createInterfaceMap(isXBLScope) {
   var interfaceMap = {};
 
   function addInterfaces(interfaces)
   {
--- a/dom/webidl/PerformanceTiming.webidl
+++ b/dom/webidl/PerformanceTiming.webidl
@@ -34,10 +34,16 @@ interface PerformanceTiming {
   readonly attribute unsigned long long loadEventEnd;
 
   // This is a Chrome proprietary extension and not part of the
   // performance/navigation timing specification.
   // Returns 0 if a non-blank paint has not happened.
   [Pref="dom.performance.time_to_non_blank_paint.enabled"]
   readonly attribute unsigned long long timeToNonBlankPaint;
 
+  // This is a Mozilla proprietary extension and not part of the
+  // performance/navigation timing specification. It marks the
+  // completion of the first presentation flush after DOMContentLoaded.
+  [Pref="dom.performance.time_to_dom_content_flushed.enabled"]
+  readonly attribute unsigned long long timeToDOMContentFlushed;
+
   jsonifier;
 };
rename from dom/webidl/PopupBoxObject.webidl
rename to dom/webidl/XULPopupElement.webidl
--- a/dom/webidl/PopupBoxObject.webidl
+++ b/dom/webidl/XULPopupElement.webidl
@@ -1,50 +1,39 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-[Func="IsChromeOrXBL"]
-interface PopupBoxObject : BoxObject
+dictionary OpenPopupOptions {
+  // manner in which to anchor the popup to node
+  DOMString position = "";
+  // horizontal offset
+  long x = 0;
+  // vertical offset
+  long y = 0;
+  // isContextMenu true for context menus, false for other popups
+  boolean isContextMenu = false;
+  // true if popup node attributes override position
+  boolean attributesOverride = false;
+  // triggerEvent the event that triggered this popup (mouse click for example)
+  Event? triggerEvent = null;
+};
+
+typedef (DOMString or OpenPopupOptions) StringOrOpenPopupOptions;
+
+[HTMLConstructor, Func="IsChromeOrXBL"]
+interface XULPopupElement : XULElement
 {
   /**
-   *  This method is deprecated. Use openPopup or openPopupAtScreen instead.
-   */
-  void showPopup(Element? srcContent, Element popupContent,
-                 long xpos, long ypos,
-                 optional DOMString popupType = "",
-                 optional DOMString anchorAlignment = "",
-                 optional DOMString popupAlignment = "");
-
-  /**
-   *  Hide the popup if it is open. The cancel argument is used as a hint that
-   *  the popup is being closed because it has been cancelled, rather than
-   *  something being selected within the panel.
-   *
-   * @param cancel if true, then the popup is being cancelled.
-   */
-  void hidePopup(optional boolean cancel = false);
-
-  /**
    * Allow the popup to automatically position itself.
    */
   attribute boolean autoPosition;
 
   /**
-   * Size the popup to the given dimensions
-   */
-  void sizeTo(long width, long height);
-
-  /**
-   * Move the popup to a point on screen in CSS pixels.
-   */
-  void moveTo(long left, long top);
-
-  /**
    * Open the popup relative to a specified node at a specific location.
    *
    * The popup may be either anchored to another node or opened freely.
    * To anchor a popup to a node, supply an anchor node and set the position
    * to a string indicating the manner in which the popup should be anchored.
    * Possible values for position are:
    *    before_start, before_end, after_start, after_end,
    *    start_before, start_after, end_before, end_after,
@@ -63,70 +52,91 @@ interface PopupBoxObject : BoxObject
    * be used to move to the left and upwards respectively.
    *
    * Unanchored popups may be created by supplying null as the anchor node.
    * An unanchored popup appears at the position specified by x and y,
    * relative to the viewport of the document containing the popup node. In
    * this case, position and attributesOverride are ignored.
    *
    * @param anchorElement the node to anchor the popup to, may be null
-   * @param position manner is which to anchor the popup to node
+   * @param options either options to use, or a string position
    * @param x horizontal offset
    * @param y vertical offset
    * @param isContextMenu true for context menus, false for other popups
    * @param attributesOverride true if popup node attributes override position
    * @param triggerEvent the event that triggered this popup (mouse click for example)
    */
-  void openPopup(Element? anchorElement,
-                 optional DOMString position = "",
-                 long x,
-                 long y,
-                 boolean isContextMenu,
-                 boolean attributesOverride,
-                 Event? triggerEvent);
+  void openPopup(optional Element? anchorElement = null,
+                 optional StringOrOpenPopupOptions options,
+                 optional long x = 0,
+                 optional long y = 0,
+                 optional boolean isContextMenu = false,
+                 optional boolean attributesOverride = false,
+                 optional Event? triggerEvent = null);
 
   /**
    * Open the popup at a specific screen position specified by x and y. This
    * position may be adjusted if it would cause the popup to be off of the
    * screen. The x and y coordinates are measured in CSS pixels, and like all
    * screen coordinates, are given relative to the top left of the primary
    * screen.
    *
    * @param isContextMenu true for context menus, false for other popups
    * @param x horizontal screen position
    * @param y vertical screen position
    * @param triggerEvent the event that triggered this popup (mouse click for example)
    */
-  void openPopupAtScreen(long x, long y,
-                         boolean isContextMenu,
-                         Event? triggerEvent);
+  void openPopupAtScreen(optional long x = 0, optional long y = 0,
+                         optional boolean isContextMenu = false,
+                         optional Event? triggerEvent = null);
 
   /**
    * Open the popup anchored at a specific screen rectangle. This function is
    * similar to openPopup except that that rectangle of the anchor is supplied
    * rather than an element. The anchor rectangle arguments are screen
    * coordinates.
    */
   void openPopupAtScreenRect(optional DOMString position = "",
-                             long x,
-                             long y,
-                             long width,
-                             long height,
-                             boolean isContextMenu,
-                             boolean attributesOverride,
-                             Event? triggerEvent);
+                             optional long x = 0,
+                             optional long y = 0,
+                             optional long width = 0,
+                             optional long height = 0,
+                             optional boolean isContextMenu = false,
+                             optional boolean attributesOverride = false,
+                             optional Event? triggerEvent = null);
+
+  /**
+   *  Hide the popup if it is open. The cancel argument is used as a hint that
+   *  the popup is being closed because it has been cancelled, rather than
+   *  something being selected within the panel.
+   *
+   * @param cancel if true, then the popup is being cancelled.
+   */
+  void hidePopup(optional boolean cancel = false);
+
+  /**
+   * Attribute getter and setter for label.
+   */
+  [SetterThrows]
+  attribute DOMString label;
+
+  /**
+   * Attribute getter and setter for position.
+   */
+  [SetterThrows]
+  attribute DOMString position;
 
   /**
    * Returns the state of the popup:
    *   closed - the popup is closed
    *   open - the popup is open
    *   showing - the popup is in the process of being shown
    *   hiding - the popup is in the process of being hidden
    */
-  readonly attribute DOMString popupState;
+  readonly attribute DOMString state;
 
   /**
    * The node that triggered the popup. If the popup is not open, will return
    * null.
    */
   readonly attribute Node? triggerNode;
 
   /**
@@ -137,24 +147,34 @@ interface PopupBoxObject : BoxObject
 
   /**
    * Retrieve the screen rectangle of the popup, including the area occupied by
    * any titlebar or borders present.
    */
   DOMRect getOuterScreenRect();
 
   /**
+   * Move the popup to a point on screen in CSS pixels.
+   */
+  void moveTo(long left, long top);
+
+  /**
    * Move an open popup to the given anchor position. The arguments have the same
    * meaning as the corresponding argument to openPopup. This method has no effect
    * on popups that are not open.
    */
-  void moveToAnchor(Element? anchorElement,
+  void moveToAnchor(optional Element? anchorElement = null,
                     optional DOMString position = "",
-                    long x, long y,
-                    boolean attributesOverride);
+                    optional long x = 0, optional long y = 0,
+                    optional boolean attributesOverride = false);
+
+  /**
+   * Size the popup to the given dimensions
+   */
+  void sizeTo(long width, long height);
 
   /** Returns the alignment position where the popup has appeared relative to its
    *  anchor node or point, accounting for any flipping that occurred.
    */
   readonly attribute DOMString alignmentPosition;
   readonly attribute long alignmentOffset;
 
   void setConstraintRect(DOMRectReadOnly rect);
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -716,17 +716,16 @@ WEBIDL_FILES = [
     'PerformanceServerTiming.webidl',
     'PerformanceTiming.webidl',
     'PeriodicWave.webidl',
     'Permissions.webidl',
     'PermissionStatus.webidl',
     'Plugin.webidl',
     'PluginArray.webidl',
     'PointerEvent.webidl',
-    'PopupBoxObject.webidl',
     'Position.webidl',
     'PositionError.webidl',
     'Presentation.webidl',
     'PresentationAvailability.webidl',
     'PresentationConnection.webidl',
     'PresentationConnectionList.webidl',
     'PresentationReceiver.webidl',
     'PresentationRequest.webidl',
@@ -948,16 +947,17 @@ WEBIDL_FILES = [
     'XPathEvaluator.webidl',
     'XPathExpression.webidl',
     'XPathNSResolver.webidl',
     'XPathResult.webidl',
     'XSLTProcessor.webidl',
     'XULCommandEvent.webidl',
     'XULDocument.webidl',
     'XULElement.webidl',
+    'XULPopupElement.webidl',
 ]
 
 if CONFIG['MOZ_WEBRTC']:
     WEBIDL_FILES += [
         'PeerConnectionImpl.webidl',
         'PeerConnectionImplEnums.webidl',
         'PeerConnectionObserver.webidl',
         'PeerConnectionObserverEnums.webidl',
--- a/dom/websocket/tests/test_websocket_frame.html
+++ b/dom/websocket/tests/test_websocket_frame.html
@@ -31,17 +31,17 @@ var innerId =
         .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
 ok(innerId, "We have a valid innerWindowID: " + innerId);
 
 var service = Cc["@mozilla.org/websocketevent/service;1"]
                 .getService(Ci.nsIWebSocketEventService);
 ok(!!service, "We have the nsIWebSocketEventService");
 
 var listener = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebSocketEventListener]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebSocketEventListener]),
 
   webSocketCreated: function(aWebSocketSerialID, aURI, aProtocols) {
     info("WebSocketCreated");
 
     is(aURI, URI, "URI matches");
     is(aProtocols, "frame", "Protocol matches");
 
     webSocketCreatedCounter++;
--- a/dom/workers/test/extensions/bootstrap/bootstrap.js
+++ b/dom/workers/test/extensions/bootstrap/bootstrap.js
@@ -91,17 +91,17 @@ WorkerTestBootstrap.prototype = {
         gWorkerAndCallback.terminate();
         break;
 
       default:
         throw new Error("Unknown worker command");
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver])
 };
 
 var gFactory = {
   register: function() {
     var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 
     var classID = Components.ID("{36b5df0b-8dcf-4aa2-9c45-c51d871295f9}");
     var description = "WorkerTestBootstrap";
--- a/dom/workers/test/test_extensionBootstrap.xul
+++ b/dom/workers/test/test_extensionBootstrap.xul
@@ -36,17 +36,17 @@
                                             "." + symbol),
                  true,
                  "Symbol '" + symbol + "' present during '" + stage + "'");
             }
           }
 
           SimpleTest.finish();
         },
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
+        QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver])
       };
 
       var workertestbootstrap = Cc["@mozilla.org/test/workertestbootstrap;1"].
                                 createInstance(Ci.nsIObserver);
 
       workertestbootstrap.observe(observer, "postMessage", message);
 
       SimpleTest.waitForExplicitFinish();
--- a/dom/xbl/nsXBLContentSink.cpp
+++ b/dom/xbl/nsXBLContentSink.cpp
@@ -869,17 +869,17 @@ nsXBLContentSink::CreateElement(const ch
   *aAppendContent = true;
   RefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
 
   prototype->mNodeInfo = aNodeInfo;
 
   AddAttributesToXULPrototype(aAtts, aAttsCount, prototype);
 
   Element* result;
-  nsresult rv = nsXULElement::Create(prototype, mDocument, false, false, &result);
+  nsresult rv = nsXULElement::CreateFromPrototype(prototype, mDocument, false, false, &result);
   *aResult = result;
   return rv;
 #endif
 }
 
 nsresult
 nsXBLContentSink::AddAttributes(const char16_t** aAtts, Element* aElement)
 {
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -1295,17 +1295,17 @@ nsXBLPrototypeBinding::ReadContentNode(n
         attrs[i].mName.SetTo(ni);
       }
 
       rv = prototype->SetAttrAt(i, val, documentURI);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     nsresult rv =
-      nsXULElement::Create(prototype, aDocument, false, false, getter_AddRefs(element));
+      nsXULElement::CreateFromPrototype(prototype, aDocument, false, false, getter_AddRefs(element));
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
 #endif
     NS_NewElement(getter_AddRefs(element), nodeInfo.forget(), NOT_FROM_PARSER);
 
     for (uint32_t i = 0; i < attrCount; i++) {
       rv = ReadNamespace(aStream, namespaceID);
       NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/xslt/xslt/txEXSLTRegExFunctions.js
+++ b/dom/xslt/xslt/txEXSLTRegExFunctions.js
@@ -11,17 +11,17 @@ function txEXSLTRegExFunctions()
 {
 }
 
 var SingletonInstance = null;
 
 txEXSLTRegExFunctions.prototype = {
     classID: EXSLT_REGEXP_CID,
 
-    QueryInterface: XPCOMUtils.generateQI([Ci.txIEXSLTRegExFunctions]),
+    QueryInterface: ChromeUtils.generateQI([Ci.txIEXSLTRegExFunctions]),
 
     // txIEXSLTRegExFunctions
     match: function(str, regex, flags, doc) {
         var docFrag = doc.createDocumentFragment();
         var re = new RegExp(regex, flags);
         var matches = str.match(re);
         if (matches != null) {
             for (var i = 0; i < matches.length; ++i) {
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -3319,17 +3319,17 @@ XULDocument::CreateElementFromPrototype(
                 NS_ConvertUTF16toUTF8(aPrototype->mNodeInfo->QualifiedName()).get()));
     }
 
     RefPtr<Element> result;
 
     if (aPrototype->mNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
         // If it's a XUL element, it'll be lightweight until somebody
         // monkeys with it.
-        rv = nsXULElement::Create(aPrototype, this, true, aIsRoot, getter_AddRefs(result));
+        rv = nsXULElement::CreateFromPrototype(aPrototype, this, true, aIsRoot, getter_AddRefs(result));
         if (NS_FAILED(rv)) return rv;
     }
     else {
         // If it's not a XUL element, it's gonna be heavyweight no matter
         // what. So we need to copy everything out of the prototype
         // into the element.  Get a nodeinfo from our nodeinfo manager
         // for this node.
         RefPtr<mozilla::dom::NodeInfo> newNodeInfo;
rename from layout/xul/PopupBoxObject.cpp
rename to dom/xul/XULPopupElement.cpp
--- a/layout/xul/PopupBoxObject.cpp
+++ b/dom/xul/XULPopupElement.cpp
@@ -9,195 +9,197 @@
 #include "nsIPresShell.h"
 #include "nsIContent.h"
 #include "nsNameSpaceManager.h"
 #include "nsGkAtoms.h"
 #include "nsMenuPopupFrame.h"
 #include "nsView.h"
 #include "mozilla/AppUnits.h"
 #include "mozilla/dom/DOMRect.h"
-#include "mozilla/dom/PopupBoxObject.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
-#include "mozilla/dom/PopupBoxObjectBinding.h"
+#include "mozilla/dom/XULPopupElement.h"
+#include "mozilla/dom/XULPopupElementBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-PopupBoxObject::PopupBoxObject()
+nsXULElement*
+NS_NewXULPopupElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
 {
+  return new XULPopupElement(aNodeInfo);
 }
 
-PopupBoxObject::~PopupBoxObject()
+JSObject*
+XULPopupElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
-}
-
-nsIContent* PopupBoxObject::GetParentObject() const
-{
-  return BoxObject::GetParentObject();
+  return XULPopupElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
-JSObject* PopupBoxObject::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+nsIFrame*
+XULPopupElement::GetFrame(bool aFlushLayout)
 {
-  return PopupBoxObjectBinding::Wrap(aCx, this, aGivenProto);
-}
+  nsCOMPtr<nsIContent> kungFuDeathGrip = this; // keep a reference
 
-nsPopupSetFrame*
-PopupBoxObject::GetPopupSetFrame()
-{
-  nsIRootBox* rootBox = nsIRootBox::GetRootBox(GetPresShell(false));
-  if (!rootBox)
-    return nullptr;
+  nsCOMPtr<nsIDocument> doc = GetUncomposedDoc();
+  if (doc) {
+    doc->FlushPendingNotifications(aFlushLayout ? FlushType::Layout : FlushType::Frames);
+  }
 
-  return rootBox->GetPopupSetFrame();
+  return GetPrimaryFrame();
 }
 
 void
-PopupBoxObject::HidePopup(bool aCancel)
+XULPopupElement::OpenPopup(Element* aAnchorElement,
+                           const StringOrOpenPopupOptions& aOptions,
+                           int32_t aXPos, int32_t aYPos,
+                           bool aIsContextMenu,
+                           bool aAttributesOverride,
+                           Event* aTriggerEvent)
 {
-  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm && mContent) {
-    pm->HidePopup(mContent, false, true, false, aCancel);
+  nsAutoString position;
+  if (aOptions.IsOpenPopupOptions()) {
+    const OpenPopupOptions& options = aOptions.GetAsOpenPopupOptions();
+    position = options.mPosition;
+    aXPos = options.mX;
+    aYPos = options.mY;
+    aIsContextMenu = options.mIsContextMenu;
+    aAttributesOverride = options.mAttributesOverride;
+    aTriggerEvent = options.mTriggerEvent;
   }
-}
+  else {
+    position = aOptions.GetAsString();
+  }
 
-void
-PopupBoxObject::ShowPopup(Element* aAnchorElement,
-                          Element& aPopupElement,
-                          int32_t aXPos, int32_t aYPos,
-                          const nsAString& aPopupType,
-                          const nsAString& aAnchorAlignment,
-                          const nsAString& aPopupAlignment)
-{
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm && mContent) {
-    nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
-    nsAutoString popupType(aPopupType);
-    nsAutoString anchor(aAnchorAlignment);
-    nsAutoString align(aPopupAlignment);
-    pm->ShowPopupWithAnchorAlign(mContent, anchorContent, anchor, align,
-                                 aXPos, aYPos,
-                                 popupType.EqualsLiteral("context"));
-  }
-}
+  if (pm) {
+    // As a special case for popups that are menus when no anchor or position are
+    // specified, open the popup with ShowMenu instead of ShowPopup so that the
+    // popup is aligned with the menu.
+    if (!aAnchorElement && position.IsEmpty() && GetPrimaryFrame()) {
+      nsMenuFrame* menu = do_QueryFrame(GetPrimaryFrame()->GetParent());
+      if (menu) {
+        pm->ShowMenu(menu->GetContent(), false, false);
+        return;
+      }
+    }
 
-void
-PopupBoxObject::OpenPopup(Element* aAnchorElement,
-                          const nsAString& aPosition,
-                          int32_t aXPos, int32_t aYPos,
-                          bool aIsContextMenu,
-                          bool aAttributesOverride,
-                          Event* aTriggerEvent)
-{
-  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm && mContent) {
-    nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
-    pm->ShowPopup(mContent, anchorContent, aPosition, aXPos, aYPos,
+    pm->ShowPopup(this, aAnchorElement, position, aXPos, aYPos,
                   aIsContextMenu, aAttributesOverride, false, aTriggerEvent);
   }
 }
 
 void
-PopupBoxObject::OpenPopupAtScreen(int32_t aXPos, int32_t aYPos,
-                                  bool aIsContextMenu,
-                                  Event* aTriggerEvent)
+XULPopupElement::OpenPopupAtScreen(int32_t aXPos, int32_t aYPos,
+                                   bool aIsContextMenu,
+                                   Event* aTriggerEvent)
 {
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm && mContent)
-    pm->ShowPopupAtScreen(mContent, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
+  if (pm) {
+    pm->ShowPopupAtScreen(this, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
+  }
 }
 
 void
-PopupBoxObject::OpenPopupAtScreenRect(const nsAString& aPosition,
-                                      int32_t aXPos, int32_t aYPos,
-                                      int32_t aWidth, int32_t aHeight,
-                                      bool aIsContextMenu,
-                                      bool aAttributesOverride,
-                                      Event* aTriggerEvent)
+XULPopupElement::OpenPopupAtScreenRect(const nsAString& aPosition,
+                                       int32_t aXPos, int32_t aYPos,
+                                       int32_t aWidth, int32_t aHeight,
+                                       bool aIsContextMenu,
+                                       bool aAttributesOverride,
+                                       Event* aTriggerEvent)
 {
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm && mContent) {
-    pm->ShowPopupAtScreenRect(mContent, aPosition,
+  if (pm) {
+    pm->ShowPopupAtScreenRect(this, aPosition,
                               nsIntRect(aXPos, aYPos, aWidth, aHeight),
                               aIsContextMenu, aAttributesOverride, aTriggerEvent);
   }
 }
 
 void
-PopupBoxObject::MoveTo(int32_t aLeft, int32_t aTop)
+XULPopupElement::HidePopup(bool aCancel)
 {
-  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm) {
+    pm->HidePopup(this, false, true, false, aCancel);
+  }
+}
+
+void
+XULPopupElement::MoveTo(int32_t aLeft, int32_t aTop)
+{
+  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
   if (menuPopupFrame) {
     menuPopupFrame->MoveTo(CSSIntPoint(aLeft, aTop), true);
   }
 }
 
 void
-PopupBoxObject::MoveToAnchor(Element* aAnchorElement,
-                             const nsAString& aPosition,
-                             int32_t aXPos, int32_t aYPos,
-                             bool aAttributesOverride)
+XULPopupElement::MoveToAnchor(Element* aAnchorElement,
+                              const nsAString& aPosition,
+                              int32_t aXPos, int32_t aYPos,
+                              bool aAttributesOverride)
 {
-  if (mContent) {
-    nsCOMPtr<nsIContent> anchorContent(do_QueryInterface(aAnchorElement));
-
-    nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(mContent->GetPrimaryFrame());
-    if (menuPopupFrame && menuPopupFrame->IsVisible()) {
-      menuPopupFrame->MoveToAnchor(anchorContent, aPosition, aXPos, aYPos, aAttributesOverride);
-    }
+  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
+  if (menuPopupFrame && menuPopupFrame->IsVisible()) {
+    menuPopupFrame->MoveToAnchor(aAnchorElement, aPosition, aXPos, aYPos, aAttributesOverride);
   }
 }
 
 void
-PopupBoxObject::SizeTo(int32_t aWidth, int32_t aHeight)
+XULPopupElement::SizeTo(int32_t aWidth, int32_t aHeight)
 {
-  if (!mContent)
-    return;
-
   nsAutoString width, height;
   width.AppendInt(aWidth);
   height.AppendInt(aHeight);
 
-  RefPtr<Element> element = mContent->AsElement();
+  nsCOMPtr<nsIContent> kungFuDeathGrip = this; // keep a reference
 
   // We only want to pass aNotify=true to SetAttr once, but must make sure
   // we pass it when a value is being changed.  Thus, we check if the height
   // is the same and if so, pass true when setting the width.
-  bool heightSame = element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters);
+  bool heightSame = AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters);
+
+  SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame);
+  SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
 
-  element->SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame);
-  element->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
+  // If the popup is open, force a reposition of the popup after resizing it
+  // with notifications set to true so that the popuppositioned event is fired.
+  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
+  if (menuPopupFrame && menuPopupFrame->PopupState() == ePopupShown) {
+    menuPopupFrame->SetPopupPosition(nullptr, false, false, true);
+  }
 }
 
 bool
-PopupBoxObject::AutoPosition()
+XULPopupElement::AutoPosition()
 {
-  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
+  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
   if (menuPopupFrame) {
     return menuPopupFrame->GetAutoPosition();
   }
   return true;
 }
 
 void
-PopupBoxObject::SetAutoPosition(bool aShouldAutoPosition)
+XULPopupElement::SetAutoPosition(bool aShouldAutoPosition)
 {
-  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
+  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
   if (menuPopupFrame) {
     menuPopupFrame->SetAutoPosition(aShouldAutoPosition);
   }
 }
 
 void
-PopupBoxObject::GetPopupState(nsString& aState)
+XULPopupElement::GetState(nsString& aState)
 {
   // set this here in case there's no frame for the popup
   aState.AssignLiteral("closed");
 
-  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
+  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
   if (menuPopupFrame) {
     switch (menuPopupFrame->PopupState()) {
       case ePopupShown:
         aState.AssignLiteral("open");
         break;
       case ePopupShowing:
       case ePopupPositioning:
       case ePopupOpening:
@@ -213,38 +215,38 @@ PopupBoxObject::GetPopupState(nsString& 
       default:
         NS_NOTREACHED("Bad popup state");
         break;
     }
   }
 }
 
 nsINode*
-PopupBoxObject::GetTriggerNode() const
+XULPopupElement::GetTriggerNode() const
 {
-  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
+  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
   return nsMenuPopupFrame::GetTriggerContent(menuPopupFrame);
 }
 
 Element*
-PopupBoxObject::GetAnchorNode() const
+XULPopupElement::GetAnchorNode() const
 {
-  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
+  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetPrimaryFrame());
   if (!menuPopupFrame) {
     return nullptr;
   }
 
   nsIContent* anchor = menuPopupFrame->GetAnchor();
   return anchor && anchor->IsElement() ? anchor->AsElement() : nullptr;
 }
 
 already_AddRefed<DOMRect>
-PopupBoxObject::GetOuterScreenRect()
+XULPopupElement::GetOuterScreenRect()
 {
-  RefPtr<DOMRect> rect = new DOMRect(mContent);
+  RefPtr<DOMRect> rect = new DOMRect(ToSupports(this));
 
   // Return an empty rectangle if the popup is not open.
   nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
   if (!menuPopupFrame || !menuPopupFrame->IsOpen()) {
     return rect.forget();
   }
 
   nsView* view = menuPopupFrame->GetView();
@@ -256,17 +258,17 @@ PopupBoxObject::GetOuterScreenRect()
       int32_t pp = menuPopupFrame->PresContext()->AppUnitsPerDevPixel();
       rect->SetLayoutRect(LayoutDeviceIntRect::ToAppUnits(screenRect, pp));
     }
   }
   return rect.forget();
 }
 
 void
-PopupBoxObject::GetAlignmentPosition(nsString& positionStr)
+XULPopupElement::GetAlignmentPosition(nsString& positionStr)
 {
   positionStr.Truncate();
 
   // This needs to flush layout.
   nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(true));
   if (!menuPopupFrame)
     return;
 
@@ -307,45 +309,35 @@ PopupBoxObject::GetAlignmentPosition(nsS
       break;
     default:
       // Leave as an empty string.
       break;
   }
 }
 
 int32_t
-PopupBoxObject::AlignmentOffset()
+XULPopupElement::AlignmentOffset()
 {
   nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
   if (!menuPopupFrame)
     return 0;
 
   int32_t pp = mozilla::AppUnitsPerCSSPixel();
   // Note that the offset might be along either the X or Y axis, but for the
   // sake of simplicity we use a point with only the X axis set so we can
   // use ToNearestPixels().
   nsPoint appOffset(menuPopupFrame->GetAlignmentOffset(), 0);
   nsIntPoint popupOffset = appOffset.ToNearestPixels(pp);
   return popupOffset.x;
 }
 
 void
-PopupBoxObject::SetConstraintRect(dom::DOMRectReadOnly& aRect)
+XULPopupElement::SetConstraintRect(dom::DOMRectReadOnly& aRect)
 {
   nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
   if (menuPopupFrame) {
     menuPopupFrame->SetOverrideConstraintRect(
       LayoutDeviceIntRect::Truncate(aRect.Left(), aRect.Top(), aRect.Width(), aRect.Height()));
   }
 }
 
 } // namespace dom
 } // namespace mozilla
-
-// Creation Routine ///////////////////////////////////////////////////////////////////////
-
-nsresult
-NS_NewPopupBoxObject(nsIBoxObject** aResult)
-{
-  *aResult = new mozilla::dom::PopupBoxObject();
-  NS_ADDREF(*aResult);
-  return NS_OK;
-}
rename from layout/xul/PopupBoxObject.h
rename to dom/xul/XULPopupElement.h
--- a/layout/xul/PopupBoxObject.h
+++ b/dom/xul/XULPopupElement.h
@@ -1,64 +1,72 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=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/. */
 
-#ifndef mozilla_dom_PopupBoxObject_h
-#define mozilla_dom_PopupBoxObject_h
+#ifndef XULPopupElement_h__
+#define XULPopupElement_h__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
-#include "mozilla/dom/BoxObject.h"
 #include "nsString.h"
+#include "nsXULElement.h"
 
 struct JSContext;
-class nsPopupSetFrame;
 
 namespace mozilla {
 namespace dom {
 
 class DOMRect;
 class Element;
 class Event;
+class StringOrOpenPopupOptions;
 
-class PopupBoxObject final : public BoxObject
+nsXULElement*
+NS_NewXULPopupElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
+
+class XULPopupElement final : public nsXULElement
 {
+private:
+  nsIFrame* GetFrame(bool aFlushLayout);
+
 public:
-  NS_INLINE_DECL_REFCOUNTING_INHERITED(PopupBoxObject, BoxObject)
-
-  PopupBoxObject();
+  explicit XULPopupElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+    : nsXULElement(aNodeInfo)
+  {
+  }
 
-  nsIContent* GetParentObject() const;
-  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+  void GetLabel(DOMString& aValue) const
+  {
+      GetXULAttr(nsGkAtoms::label, aValue);
+  }
+  void SetLabel(const nsAString& aValue, ErrorResult& rv)
+  {
+      SetXULAttr(nsGkAtoms::label, aValue, rv);
+  }
 
-  void ShowPopup(Element* aAnchorElement,
-                 Element& aPopupElement,
-                 int32_t aXPos,
-                 int32_t aYPos,
-                 const nsAString& aPopupType,
-                 const nsAString& aAnchorAlignment,
-                 const nsAString& aPopupAlignment);
-
-  void HidePopup(bool aCancel);
+  void GetPosition(DOMString& aValue) const
+  {
+      GetXULAttr(nsGkAtoms::position, aValue);
+  }
+  void SetPosition(const nsAString& aValue, ErrorResult& rv)
+  {
+      SetXULAttr(nsGkAtoms::position, aValue, rv);
+  }
 
   bool AutoPosition();
 
   void SetAutoPosition(bool aShouldAutoPosition);
 
-  void SizeTo(int32_t aWidth, int32_t aHeight);
-
-  void MoveTo(int32_t aLeft, int32_t aTop);
-
   void OpenPopup(Element* aAnchorElement,
-                 const nsAString& aPosition,
+                 const StringOrOpenPopupOptions& aOptions,
                  int32_t aXPos,
                  int32_t aYPos,
                  bool aIsContextMenu, bool aAttributesOverride,
                  Event* aTriggerEvent);
 
   void OpenPopupAtScreen(int32_t aXPos,
                          int32_t aYPos,
                          bool aIsContextMenu,
@@ -66,39 +74,46 @@ public:
 
   void OpenPopupAtScreenRect(const nsAString& aPosition,
                              int32_t aXPos, int32_t aYPos,
                              int32_t aWidth, int32_t aHeight,
                              bool aIsContextMenu,
                              bool aAttributesOverride,
                              Event* aTriggerEvent);
 
-  void GetPopupState(nsString& aState);
+  void HidePopup(bool aCancel);
+
+  void GetState(nsString& aState);
 
   nsINode* GetTriggerNode() const;
 
   Element* GetAnchorNode() const;
 
   already_AddRefed<DOMRect> GetOuterScreenRect();
 
+  void MoveTo(int32_t aLeft, int32_t aTop);
+
   void MoveToAnchor(Element* aAnchorElement,
                     const nsAString& aPosition,
                     int32_t aXPos,
                     int32_t aYPos,
                     bool aAttributesOverride);
 
+  void SizeTo(int32_t aWidth, int32_t aHeight);
+
   void GetAlignmentPosition(nsString& positionStr);
 
   int32_t AlignmentOffset();
 
-  void SetConstraintRect(dom::DOMRectReadOnly& aRect);
-
-private:
-  ~PopupBoxObject();
+  void SetConstraintRect(DOMRectReadOnly& aRect);
 
 protected:
-  nsPopupSetFrame* GetPopupSetFrame();
+  virtual ~XULPopupElement()
+  {
+  }
+
+  JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_PopupBoxObject_h
+#endif // XULPopupElement_h
--- a/dom/xul/crashtests/384877-1-inner.xul
+++ b/dom/xul/crashtests/384877-1-inner.xul
@@ -2,14 +2,11 @@
 <script>
 function doe() {
 var d = document.getElementById('d');
 if (d.openPopup) {
   d.openPopup(document.documentElement, 'before_start', 0, 0, false, false);
 //  alert(d.state);
 }
   
-if (d.showPopup)
-  d.showPopup();
-}
 setTimeout(doe, 200);
 </script>
 </menupopup>
--- a/dom/xul/moz.build
+++ b/dom/xul/moz.build
@@ -18,26 +18,31 @@ if CONFIG['MOZ_XUL']:
     XPIDL_SOURCES += [
         'nsIXULOverlayProvider.idl',
     ]
 
     EXPORTS += [
         'nsXULElement.h',
     ]
 
+    EXPORTS.mozilla.dom += [
+        'XULPopupElement.h',
+    ]
+
     UNIFIED_SOURCES += [
         'nsXULCommandDispatcher.cpp',
         'nsXULContentSink.cpp',
         'nsXULContentUtils.cpp',
         'nsXULElement.cpp',
         'nsXULPopupListener.cpp',
         'nsXULPrototypeCache.cpp',
         'nsXULPrototypeDocument.cpp',
         'nsXULSortService.cpp',
         'XULDocument.cpp',
+        'XULPopupElement.cpp',
     ]
 
 XPIDL_SOURCES += [
     'nsIController.idl',
     'nsIControllers.idl',
     'nsIXULSortService.idl',
 ]
 
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -70,16 +70,17 @@
 #include "nsNodeInfoManager.h"
 #include "nsXBLBinding.h"
 #include "nsXULTooltipListener.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozAutoDocUpdate.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsICSSDeclaration.h"
 #include "nsLayoutUtils.h"
+#include "XULPopupElement.h"
 
 #include "mozilla/dom/XULElementBinding.h"
 #include "mozilla/dom/BoxObject.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/MouseEventBinding.h"
 #include "mozilla/dom/MutationEventBinding.h"
 #include "mozilla/dom/XULCommandEvent.h"
 
@@ -123,17 +124,17 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULEl
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULElementTearoff)
   NS_INTERFACE_MAP_ENTRY(nsIFrameLoaderOwner)
 NS_INTERFACE_MAP_END_AGGREGATED(mElement)
 
 //----------------------------------------------------------------------
 // nsXULElement
 //
 
-nsXULElement::nsXULElement(already_AddRefed<mozilla::dom::NodeInfo> aNodeInfo)
+nsXULElement::nsXULElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : nsStyledElement(aNodeInfo),
       mBindingParent(nullptr)
 {
     XUL_PROTOTYPE_ATTRIBUTE_METER(gNumElements);
 
     // We may be READWRITE by default; check.
     if (IsReadWriteTextElement()) {
         AddStatesSilently(NS_EVENT_STATE_MOZ_READWRITE);
@@ -157,19 +158,41 @@ nsXULElement::MaybeUpdatePrivateLifetime
     nsPIDOMWindowOuter* win = OwnerDoc()->GetWindow();
     nsCOMPtr<nsIDocShell> docShell = win ? win->GetDocShell() : nullptr;
     if (docShell) {
         docShell->SetAffectPrivateSessionLifetime(false);
     }
 }
 
 /* static */
+nsXULElement* NS_NewBasicXULElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
+{
+  return new nsXULElement(aNodeInfo);
+}
+
+ /* static */
+nsXULElement* nsXULElement::Construct(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
+{
+  RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
+  if (nodeInfo->Equals(nsGkAtoms::menupopup) ||
+      nodeInfo->Equals(nsGkAtoms::popup) ||
+      nodeInfo->Equals(nsGkAtoms::panel) ||
+      nodeInfo->Equals(nsGkAtoms::tooltip)) {
+    return NS_NewXULPopupElement(nodeInfo.forget());
+  }
+
+  return NS_NewBasicXULElement(nodeInfo.forget());
+}
+
+/* static */
 already_AddRefed<nsXULElement>
-nsXULElement::Create(nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo *aNodeInfo,
-                     bool aIsScriptable, bool aIsRoot)
+nsXULElement::CreateFromPrototype(nsXULPrototypeElement* aPrototype,
+                                  mozilla::dom::NodeInfo *aNodeInfo,
+                                  bool aIsScriptable,
+                                  bool aIsRoot)
 {
     RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
     nsCOMPtr<Element> baseElement;
     NS_NewXULElement(getter_AddRefs(baseElement), ni.forget(), dom::FROM_PARSER_NETWORK);
 
     if (baseElement) {
         nsXULElement* element = FromNode(baseElement);
 
@@ -204,21 +227,21 @@ nsXULElement::Create(nsXULPrototypeEleme
 
         return baseElement.forget().downcast<nsXULElement>();
     }
 
     return nullptr;
 }
 
 nsresult
-nsXULElement::Create(nsXULPrototypeElement* aPrototype,
-                     nsIDocument* aDocument,
-                     bool aIsScriptable,
-                     bool aIsRoot,
-                     Element** aResult)
+nsXULElement::CreateFromPrototype(nsXULPrototypeElement* aPrototype,
+                                  nsIDocument* aDocument,
+                                  bool aIsScriptable,
+                                  bool aIsRoot,
+                                  Element** aResult)
 {
     // Create an nsXULElement from a prototype
     NS_PRECONDITION(aPrototype != nullptr, "null ptr");
     if (! aPrototype)
         return NS_ERROR_NULL_POINTER;
 
     NS_PRECONDITION(aResult != nullptr, "null ptr");
     if (! aResult)
@@ -229,18 +252,18 @@ nsXULElement::Create(nsXULPrototypeEleme
         mozilla::dom::NodeInfo* ni = aPrototype->mNodeInfo;
         nodeInfo = aDocument->NodeInfoManager()->
           GetNodeInfo(ni->NameAtom(), ni->GetPrefixAtom(), ni->NamespaceID(),
                       ELEMENT_NODE);
     } else {
         nodeInfo = aPrototype->mNodeInfo;
     }
 
-    RefPtr<nsXULElement> element = Create(aPrototype, nodeInfo,
-                                            aIsScriptable, aIsRoot);
+    RefPtr<nsXULElement> element = CreateFromPrototype(aPrototype, nodeInfo,
+                                                       aIsScriptable, aIsRoot);
     element.forget(aResult);
 
     return NS_OK;
 }
 
 nsresult
 NS_NewXULElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                  FromParser aFromParser)
@@ -263,17 +286,17 @@ NS_NewXULElement(Element** aResult, alre
 void
 NS_TrustedNewXULElement(Element** aResult,
                         already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
 {
     RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
     NS_PRECONDITION(ni, "need nodeinfo for non-proto Create");
 
     // Create an nsXULElement with the specified namespace and tag.
-    NS_ADDREF(*aResult = new nsXULElement(ni.forget()));
+    NS_ADDREF(*aResult = nsXULElement::Construct(ni.forget()));
 }
 
 //----------------------------------------------------------------------
 // nsISupports interface
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULElement,
@@ -301,17 +324,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsStyled
 
 nsresult
 nsXULElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                     bool aPreallocateChildren) const
 {
     *aResult = nullptr;
 
     RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
-    RefPtr<nsXULElement> element = new nsXULElement(ni.forget());
+    RefPtr<nsXULElement> element = Construct(ni.forget());
 
     nsresult rv = element->mAttrsAndChildren.EnsureCapacityToClone(mAttrsAndChildren,
                                                                    aPreallocateChildren);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Note that we're _not_ copying mControllers.
 
     uint32_t count = mAttrsAndChildren.AttrCount();
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -327,27 +327,36 @@ enum {
   XUL_ELEMENT_HAS_CONTENTMENU_LISTENER =  XUL_ELEMENT_FLAG_BIT(0),
   XUL_ELEMENT_HAS_POPUP_LISTENER =        XUL_ELEMENT_FLAG_BIT(1)
 };
 
 ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
 
 #undef XUL_ELEMENT_FLAG_BIT
 
-class nsXULElement final : public nsStyledElement,
-                           public nsIDOMNode
+class nsXULElement : public nsStyledElement,
+                     public nsIDOMNode
 {
+protected:
+    // Use Construct to construct elements instead of this constructor.
+    explicit nsXULElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
+
 public:
     using Element::Blur;
     using Element::Focus;
-    explicit nsXULElement(already_AddRefed<mozilla::dom::NodeInfo> aNodeInfo);
 
     static nsresult
-    Create(nsXULPrototypeElement* aPrototype, nsIDocument* aDocument,
-           bool aIsScriptable, bool aIsRoot, mozilla::dom::Element** aResult);
+    CreateFromPrototype(nsXULPrototypeElement* aPrototype,
+                        nsIDocument* aDocument,
+                        bool aIsScriptable,
+                        bool aIsRoot,
+                        mozilla::dom::Element** aResult);
+
+    // This is the constructor for nsXULElements.
+    static nsXULElement* Construct(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
     NS_IMPL_FROMNODE(nsXULElement, kNameSpaceID_XUL)
 
     // nsISupports
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULElement, nsStyledElement)
 
     // nsINode
@@ -718,25 +727,30 @@ protected:
     nsIControllers *Controllers() {
       nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
       return slots ? slots->mControllers.get() : nullptr;
     }
 
     void UnregisterAccessKey(const nsAString& aOldValue);
     bool BoolAttrIsTrue(nsAtom* aName) const;
 
+    friend nsXULElement*
+    NS_NewBasicXULElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
+
     friend nsresult
     NS_NewXULElement(mozilla::dom::Element** aResult, mozilla::dom::NodeInfo *aNodeInfo,
                      mozilla::dom::FromParser aFromParser, const nsAString* aIs);
     friend void
     NS_TrustedNewXULElement(mozilla::dom::Element** aResult, mozilla::dom::NodeInfo *aNodeInfo);
 
     static already_AddRefed<nsXULElement>
-    Create(nsXULPrototypeElement* aPrototype, mozilla::dom::NodeInfo *aNodeInfo,
-           bool aIsScriptable, bool aIsRoot);
+    CreateFromPrototype(nsXULPrototypeElement* aPrototype,
+                        mozilla::dom::NodeInfo *aNodeInfo,
+                        bool aIsScriptable,
+                        bool aIsRoot);
 
     bool IsReadWriteTextElement() const
     {
         return IsAnyOfXULElements(nsGkAtoms::textbox, nsGkAtoms::textarea) &&
                !HasAttr(kNameSpaceID_None, nsGkAtoms::readonly);
     }
 
     virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/editor/composer/test/test_bug1266815.html
+++ b/editor/composer/test/test_bug1266815.html
@@ -33,17 +33,17 @@ var helperAppDlgPromise = new Promise(fu
 
   HelperAppLauncherDialog.prototype = {
     show: function(aLauncher, aWindowContext, aReason) {
       ok(true, "Whether showing Dialog");
       resolve();
       registrar.unregisterFactory(MOCK_HELPERAPP_DIALOG_CID,
                                   mockHelperAppService);
     },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
   };
 
   mockHelperAppService = XPCOMUtils._getFactory(HelperAppLauncherDialog);
   registrar.registerFactory(MOCK_HELPERAPP_DIALOG_CID, "",
                             HELPERAPP_DIALOG_CONTRACT_ID,
                             mockHelperAppService);
 });
 
--- a/editor/libeditor/EditorUtils.js
+++ b/editor/libeditor/EditorUtils.js
@@ -9,17 +9,17 @@ ChromeUtils.import("resource://gre/modul
 
 const EDITORUTILS_CID = Components.ID('{12e63991-86ac-4dff-bb1a-703495d67d17}');
 
 function EditorUtils() {
 }
 
 EditorUtils.prototype = {
   classID: EDITORUTILS_CID,
-  QueryInterface: XPCOMUtils.generateQI([ Ci.nsIEditorUtils ]),
+  QueryInterface: ChromeUtils.generateQI([ Ci.nsIEditorUtils ]),
 
   slurpBlob(aBlob, aScope, aListener) {
     let reader = new aScope.FileReader();
     reader.addEventListener("load", (event) => {
       aListener.onResult(event.target.result);
     });
     reader.addEventListener("error", (event) => {
       aListener.onError(event.target.error.message);
--- a/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js
+++ b/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js
@@ -10,17 +10,17 @@ var PERMISSIONS_FILE_NAME = "permissions
 var CONTRACT_ID = "@mozilla.org/browser/nav-history-service;1";
 var factory = {
   createInstance: function() {
     throw new Error("There is no history service");
   },
   lockFactory: function() {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIFactory])
 };
 
 var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
 
 var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 var oldClassID = registrar.contractIDToCID(CONTRACT_ID);
 var oldFactory = Components.manager.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
 registrar.unregisterFactory(oldClassID, oldFactory);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -303,17 +303,16 @@ public:
     return NS_OK;
   }
 };
 
 NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter)
 
 gfxWindowsPlatform::gfxWindowsPlatform()
   : mRenderMode(RENDER_GDI)
-  , mUsingDirectWrite(false)
 {
   /*
    * Initialize COM
    */
   CoInitialize(nullptr);
 
   RegisterStrongMemoryReporter(new GfxD2DVramReporter());
   RegisterStrongMemoryReporter(new GPUAdapterReporter());
@@ -557,28 +556,30 @@ gfxWindowsPlatform::CreatePlatformFontLi
 {
     gfxPlatformFontList *pfl;
 
     // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd
     // crashers so blacklist them altogether
     if (IsNotWin7PreRTM() && DWriteEnabled()) {
         pfl = new gfxDWriteFontList();
         if (NS_SUCCEEDED(pfl->InitFontList())) {
-            mUsingDirectWrite = true;
             return pfl;
         }
         // DWrite font initialization failed! Don't know why this would happen,
         // but apparently it can - see bug 594865.
         // So we're going to fall back to GDI fonts & rendering.
         gfxPlatformFontList::Shutdown();
         DisableD2D(FeatureStatus::Failed, "Failed to initialize fonts",
                    NS_LITERAL_CSTRING("FEATURE_FAILURE_FONT_FAIL"));
     }
 
-    mUsingDirectWrite = false;
+    // Ensure this is false, even if the Windows version was recent enough to
+    // permit it, as we're using GDI fonts.
+    mHasVariationFontSupport = false;
+
     pfl = new gfxGDIFontList();
 
     if (NS_SUCCEEDED(pfl->InitFontList())) {
         return pfl;
     }
 
     gfxPlatformFontList::Shutdown();
     return nullptr;
@@ -2065,11 +2066,11 @@ gfxWindowsPlatform::SupportsPluginDirect
     return false;
   }
   return true;
 }
 
 bool
 gfxWindowsPlatform::CheckVariationFontSupport()
 {
-  // Variation font support is only on Fall Creators Update or later
-  return mUsingDirectWrite && IsWin10FallCreatorsUpdateOrLater();
+  // Variation font support is only available on Fall Creators Update or later.
+  return IsWin10FallCreatorsUpdateOrLater();
 }
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -262,13 +262,11 @@ private:
     void InitializeAdvancedLayersConfig();
 
     RefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
     DWRITE_MEASURING_MODE mMeasuringMode;
 
     RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
 
     nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels;
-
-    bool mUsingDirectWrite;
 };
 
 #endif /* GFX_WINDOWS_PLATFORM_H */
--- a/intl/l10n/Localization.jsm
+++ b/intl/l10n/Localization.jsm
@@ -16,17 +16,16 @@
  */
 
 
 /* fluent-dom@0.2.0 */
 
 /* eslint no-console: ["error", { allow: ["warn", "error"] }] */
 /* global console */
 
-const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {});
 const { L10nRegistry } = ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm", {});
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
 const { AppConstants } = ChromeUtils.import("resource://gre/modules/AppConstants.jsm", {});
 
 /*
  * CachedAsyncIterable caches the elements yielded by an iterable.
  *
  * It can be used to iterate over an iterable many times without depleting the
@@ -272,17 +271,17 @@ class Localization {
    * This method should be called when there's a reason to believe
    * that language negotiation or available resources changed.
    */
   onLanguageChange() {
     this.ctxs = new CachedAsyncIterable(this.generateMessages(this.resourceIds));
   }
 }
 
-Localization.prototype.QueryInterface = XPCOMUtils.generateQI([
+Localization.prototype.QueryInterface = ChromeUtils.generateQI([
   Ci.nsISupportsWeakReference
 ]);
 
 /**
  * Format the value of a message into a string.
  *
  * This function is passed as a method to `keysFromContext` and resolve
  * a value of a single L10n Entity using provided `MessageContext`.
new file mode 100644
--- /dev/null
+++ b/js/src/frontend/BCEParserHandle.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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/. */
+
+#ifndef frontend_BCEParserHandle_h
+#define frontend_BCEParserHandle_h
+
+#include "frontend/ErrorReporter.h"
+#include "frontend/FullParseHandler.h"
+#include "frontend/Parser.h"
+
+namespace js {
+namespace frontend {
+
+struct BCEParserHandle {
+    virtual ErrorReporter& errorReporter() = 0;
+    virtual const ErrorReporter& errorReporter() const = 0;
+
+    virtual const JS::ReadOnlyCompileOptions& options() = 0;
+
+    virtual FullParseHandler& astGenerator() = 0;
+    virtual ObjectBox* newObjectBox(JSObject *obj) = 0;
+};
+
+} // namespace frontend
+} // namespace js
+
+#endif // frontend_BCEParserHandle_h
--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -370,19 +370,51 @@ BinASTParser<Tok>::poison()
 
 template<typename Tok> void
 BinASTParser<Tok>::reportErrorNoOffsetVA(unsigned errorNumber, va_list args)
 {
     ErrorMetadata metadata;
     metadata.filename = getFilename();
     metadata.lineNumber = 0;
     metadata.columnNumber = offset();
+    metadata.isMuted = options().mutedErrors();
     ReportCompileError(cx_, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
 }
 
+template<typename Tok> void
+BinASTParser<Tok>::errorAtVA(uint32_t offset, unsigned errorNumber, va_list* args)
+{
+    ErrorMetadata metadata;
+    metadata.filename = getFilename();
+    metadata.lineNumber = 0;
+    metadata.columnNumber = offset;
+    metadata.isMuted = options().mutedErrors();
+    ReportCompileError(cx_, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, *args);
+}
+
+template<typename Tok> bool
+BinASTParser<Tok>::reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, unsigned errorNumber, va_list* args)
+{
+    if (!options().extraWarningsOption)
+        return true;
+
+    ErrorMetadata metadata;
+    metadata.filename = getFilename();
+    metadata.lineNumber = 0;
+    metadata.columnNumber = offset;
+    metadata.isMuted = options().mutedErrors();
+
+    if (options().werrorOption) {
+        ReportCompileError(cx_, Move(metadata), Move(notes), JSREPORT_STRICT, errorNumber, *args);
+        return false;
+    }
+
+    return ReportCompileWarning(cx_, Move(metadata), Move(notes), JSREPORT_STRICT | JSREPORT_WARNING, errorNumber, *args);
+}
+
 bool
 BinASTParserBase::hasUsedName(HandlePropertyName name)
 {
     if (UsedNamePtr p = usedNames_.lookup(name))
         return p->value().isUsedInScript(parseContext_->scriptId());
 
     return false;
 }
--- a/js/src/frontend/BinSource.h
+++ b/js/src/frontend/BinSource.h
@@ -224,33 +224,49 @@ class BinASTParser : public BinASTParser
   private: // Implement ErrorReporter
     const ReadOnlyCompileOptions& options_;
 
     const ReadOnlyCompileOptions& options() const override {
         return this->options_;
     }
 
     virtual void lineAndColumnAt(size_t offset, uint32_t* line, uint32_t* column) const override {
-        *line = 0;
-        *column = offset;
+        *line = lineAt(offset);
+        *column = columnAt(offset);
+    }
+    virtual uint32_t lineAt(size_t offset) const override {
+        return 0;
+    }
+    virtual uint32_t columnAt(size_t offset) const override {
+        return offset;
     }
+
+    virtual bool isOnThisLine(size_t offset, uint32_t lineNum, bool *isOnSameLine) const override {
+        if (lineNum != 0)
+            return false;
+        *isOnSameLine = true;
+        return true;
+    }
+
     virtual void currentLineAndColumn(uint32_t* line, uint32_t* column) const override {
         *line = 0;
         *column = offset();
     }
     size_t offset() const {
         if (tokenizer_.isSome())
             return tokenizer_->offset();
 
         return 0;
     }
     virtual bool hasTokenizationStarted() const override {
         return tokenizer_.isSome();
     }
     virtual void reportErrorNoOffsetVA(unsigned errorNumber, va_list args) override;
+    virtual void errorAtVA(uint32_t offset, unsigned errorNumber, va_list* args) override;
+    virtual bool reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, unsigned errorNumber, va_list* args) override;
     virtual const char* getFilename() const override {
         return this->options_.filename();
     }
 
     Maybe<Tokenizer> tokenizer_;
     VariableDeclarationKind variableDeclarationKind_;
 
     friend class BinParseContext;
@@ -289,9 +305,9 @@ class BinParseContext : public ParseCont
 
 
 extern template class BinASTParser<BinTokenReaderMultipart>;
 extern template class BinASTParser<BinTokenReaderTester>;
 
 } // namespace frontend
 } // namespace js
 
-#endif // frontend_BinSource_h
\ No newline at end of file
+#endif // frontend_BinSource_h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -20,17 +20,16 @@
 
 #include "jsapi.h"
 #include "jsnum.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 #include "ds/Nestable.h"
 #include "frontend/Parser.h"
-#include "frontend/TokenStream.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/Debugger.h"
 #include "vm/GeneratorObject.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 #include "vm/JSScript.h"
 #include "vm/Stack.h"
@@ -2136,29 +2135,29 @@ class ForOfLoopControl : public LoopCont
             if (!bce->emit1(JSOP_POP))                    //
                 return false;
         }
 
         return true;
     }
 };
 
+
 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
-                                 const EitherParser<FullParseHandler>& parser, SharedContext* sc,
-                                 HandleScript script, Handle<LazyScript*> lazyScript,
+                                 SharedContext* sc, HandleScript script,
+                                 Handle<LazyScript*> lazyScript,
                                  uint32_t lineNum, EmitterMode emitterMode)
   : sc(sc),
     cx(sc->context),
     parent(parent),
     script(cx, script),
     lazyScript(cx, lazyScript),
     prologue(cx, lineNum),
     main(cx, lineNum),
     current(&main),
-    parser(parser),
     atomIndices(cx->frontendCollectionPool()),
     firstLine(lineNum),
     maxFixedSlots(0),
     maxStackDepth(0),
     stackDepth(0),
     emitLevel(0),
     bodyScopeIndex(UINT32_MAX),
     varEmitterScope(nullptr),
@@ -2170,29 +2169,45 @@ BytecodeEmitter::BytecodeEmitter(Bytecod
     tryNoteList(cx),
     scopeNoteList(cx),
     yieldAndAwaitOffsetList(cx),
     typesetCount(0),
     hasSingletons(false),
     hasTryFinally(false),
     emittingRunOnceLambda(false),
     emitterMode(emitterMode),
+    scriptStartOffsetSet(false),
     functionBodyEndPosSet(false)
 {
     MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
 }
 
 BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
-                                 const EitherParser<FullParseHandler>& parser, SharedContext* sc,
+                                 BCEParserHandle* handle, SharedContext* sc,
+                                 HandleScript script, Handle<LazyScript*> lazyScript,
+                                 uint32_t lineNum, EmitterMode emitterMode)
+    : BytecodeEmitter(parent, sc, script, lazyScript, lineNum, emitterMode)
+{
+    parser = handle;
+}
+
+BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
+                                 const EitherParser& parser, SharedContext* sc,
                                  HandleScript script, Handle<LazyScript*> lazyScript,
-                                 TokenPos bodyPosition, EmitterMode emitterMode)
-    : BytecodeEmitter(parent, parser, sc, script, lazyScript,
-                      parser.tokenStream().srcCoords.lineNum(bodyPosition.begin),
-                      emitterMode)
-{
+                                 uint32_t lineNum, EmitterMode emitterMode)
+    : BytecodeEmitter(parent, sc, script, lazyScript, lineNum, emitterMode)
+{
+    ep_.emplace(parser);
+    this->parser = ep_.ptr();
+}
+
+void
+BytecodeEmitter::initFromBodyPosition(TokenPos bodyPosition)
+{
+    setScriptStartOffsetIfUnset(bodyPosition);
     setFunctionBodyEndPos(bodyPosition);
 }
 
 bool
 BytecodeEmitter::init()
 {
     return atomIndices.acquire(cx);
 }
@@ -2522,25 +2537,25 @@ LengthOfSetLine(unsigned line)
 {
     return 1 /* SRC_SETLINE */ + (line > SN_4BYTE_OFFSET_MASK ? 4 : 1);
 }
 
 /* Updates line number notes, not column notes. */
 bool
 BytecodeEmitter::updateLineNumberNotes(uint32_t offset)
 {
-    TokenStreamAnyChars* ts = &parser.tokenStream();
+    ErrorReporter* er = &parser->errorReporter();
     bool onThisLine;
-    if (!ts->srcCoords.isOnThisLine(offset, currentLine(), &onThisLine)) {
-        ts->reportErrorNoOffset(JSMSG_OUT_OF_MEMORY);
+    if (!er->isOnThisLine(offset, currentLine(), &onThisLine)) {
+        er->reportErrorNoOffset(JSMSG_OUT_OF_MEMORY);
         return false;
     }
 
     if (!onThisLine) {
-        unsigned line = ts->srcCoords.lineNum(offset);
+        unsigned line = er->lineAt(offset);
         unsigned delta = line - currentLine();
 
         /*
          * Encode any change in the current source line number by using
          * either several SRC_NEWLINE notes or just one SRC_SETLINE note,
          * whichever consumes less space.
          *
          * NB: We handle backward line number deltas (possible with for
@@ -2566,17 +2581,17 @@ BytecodeEmitter::updateLineNumberNotes(u
 
 /* Updates the line number and column number information in the source notes. */
 bool
 BytecodeEmitter::updateSourceCoordNotes(uint32_t offset)
 {
     if (!updateLineNumberNotes(offset))
         return false;
 
-    uint32_t columnIndex = parser.tokenStream().srcCoords.columnIndex(offset);
+    uint32_t columnIndex = parser->errorReporter().columnAt(offset);
     ptrdiff_t colspan = ptrdiff_t(columnIndex) - ptrdiff_t(current->lastColumn);
     if (colspan != 0) {
         // If the column span is so large that we can't store it, then just
         // discard this information. This can happen with minimized or otherwise
         // machine-generated code. Even gigantic column numbers are still
         // valuable if you have a source map to relate them to something real;
         // but it's better to fail soft here.
         if (!SN_REPRESENTABLE_COLSPAN(colspan))
@@ -3519,100 +3534,54 @@ BytecodeEmitter::needsImplicitThis()
     for (EmitterScope* es = innermostEmitterScope; es; es = es->enclosingInFrame()) {
         if (es->scope(this)->kind() == ScopeKind::With)
             return true;
     }
 
     return false;
 }
 
-bool
-BytecodeEmitter::maybeSetDisplayURL()
-{
-    if (tokenStream().hasDisplayURL()) {
-        if (!parser.ss()->setDisplayURL(cx, tokenStream().displayURL()))
-            return false;
-    }
-    return true;
-}
-
-bool
-BytecodeEmitter::maybeSetSourceMap()
-{
-    if (tokenStream().hasSourceMapURL()) {
-        MOZ_ASSERT(!parser.ss()->hasSourceMapURL());
-        if (!parser.ss()->setSourceMapURL(cx, tokenStream().sourceMapURL()))
-            return false;
-    }
-
-    /*
-     * Source map URLs passed as a compile option (usually via a HTTP source map
-     * header) override any source map urls passed as comment pragmas.
-     */
-    if (parser.options().sourceMapURL()) {
-        // Warn about the replacement, but use the new one.
-        if (parser.ss()->hasSourceMapURL()) {
-            if (!parser.warningNoOffset(JSMSG_ALREADY_HAS_PRAGMA,
-                                        parser.ss()->filename(), "//# sourceMappingURL"))
-            {
-                return false;
-            }
-        }
-
-        if (!parser.ss()->setSourceMapURL(cx, parser.options().sourceMapURL()))
-            return false;
-    }
-
-    return true;
-}
-
 void
 BytecodeEmitter::tellDebuggerAboutCompiledScript(JSContext* cx)
 {
     // Note: when parsing off thread the resulting scripts need to be handed to
     // the debugger after rejoining to the main thread.
     if (cx->helperThread())
         return;
 
     // Lazy scripts are never top level (despite always being invoked with a
     // nullptr parent), and so the hook should never be fired.
     if (emitterMode != LazyFunction && !parent)
         Debugger::onNewScript(cx, script);
 }
 
-inline TokenStreamAnyChars&
-BytecodeEmitter::tokenStream()
-{
-    return parser.tokenStream();
-}
-
 void
 BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...)
 {
-    TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
+    MOZ_ASSERT_IF(!pn, this->scriptStartOffsetSet);
+    uint32_t offset = pn ? pn->pn_pos.begin : this->scriptStartOffset;
 
     va_list args;
     va_start(args, errorNumber);
 
-    ErrorMetadata metadata;
-    if (parser.computeErrorMetadata(&metadata, pos.begin))
-        ReportCompileError(cx, Move(metadata), nullptr, JSREPORT_ERROR, errorNumber, args);
+    parser->errorReporter().errorAtVA(offset, errorNumber, &args);
 
     va_end(args);
 }
 
 bool
 BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...)
 {
-    TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos;
+    MOZ_ASSERT_IF(!pn, this->scriptStartOffsetSet);
+    uint32_t offset = pn ? pn->pn_pos.begin : this->scriptStartOffset;
 
     va_list args;
     va_start(args, errorNumber);
 
-    bool result = parser.reportExtraWarningErrorNumberVA(nullptr, pos.begin, errorNumber, &args);
+    bool result = parser->errorReporter().reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, &args);
 
     va_end(args);
     return result;
 }
 
 bool
 BytecodeEmitter::emitNewInit(JSProtoKey key)
 {
@@ -3644,17 +3613,17 @@ BytecodeEmitter::iteratorResultShape(uns
 
     Rooted<jsid> value_id(cx, NameToId(cx->names().value));
     Rooted<jsid> done_id(cx, NameToId(cx->names().done));
     if (!NativeDefineDataProperty(cx, obj, value_id, UndefinedHandleValue, JSPROP_ENUMERATE))
         return false;
     if (!NativeDefineDataProperty(cx, obj, done_id, UndefinedHandleValue, JSPROP_ENUMERATE))
         return false;
 
-    ObjectBox* objbox = parser.newObjectBox(obj);
+    ObjectBox* objbox = parser->newObjectBox(obj);
     if (!objbox)
         return false;
 
     *shape = objectList.add(objbox);
 
     return true;
 }
 
@@ -4465,17 +4434,17 @@ BytecodeEmitter::emitSwitch(ParseNode* p
     // After entering the scope, push the switch control.
     BreakableControl controlInfo(this, StatementKind::Switch);
 
     ptrdiff_t top = offset();
 
     // Switch bytecodes run from here till end of final case.
     uint32_t caseCount = cases->pn_count;
     if (caseCount > JS_BIT(16)) {
-        parser.reportError(JSMSG_TOO_MANY_CASES);
+        reportError(pn, JSMSG_TOO_MANY_CASES);
         return false;
     }
 
     // Try for most optimal, fall back if not dense ints.
     JSOp switchOp = JSOP_TABLESWITCH;
     uint32_t tableLength = 0;
     int32_t low, high;
     bool hasDefault = false;
@@ -4853,17 +4822,19 @@ BytecodeEmitter::emitSetThis(ParseNode* 
     }
 
     return emitSetOrInitializeNameAtLocation(name, lexicalLoc, emitRhs, true);
 }
 
 bool
 BytecodeEmitter::emitScript(ParseNode* body)
 {
-    AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, tokenStream(), body);
+    AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, parser->errorReporter(), body);
+
+    setScriptStartOffsetIfUnset(body->pn_pos);
 
     TDZCheckCache tdzCache(this);
     EmitterScope emitterScope(this);
     if (sc->isGlobalContext()) {
         switchToPrologue();
         if (!emitterScope.enterGlobal(this, sc->asGlobalContext()))
             return false;
         switchToMain();
@@ -4911,31 +4882,28 @@ BytecodeEmitter::emitScript(ParseNode* b
         return false;
 
     if (!emitterScope.leave(this))
         return false;
 
     if (!JSScript::fullyInitFromEmitter(cx, script, this))
         return false;
 
-    // URL and source map information must be set before firing
-    // Debugger::onNewScript.
-    if (!maybeSetDisplayURL() || !maybeSetSourceMap())
-        return false;
-
     tellDebuggerAboutCompiledScript(cx);
 
     return true;
 }
 
 bool
 BytecodeEmitter::emitFunctionScript(ParseNode* body)
 {
     FunctionBox* funbox = sc->asFunctionBox();
-    AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, tokenStream(), funbox);
+    AutoFrontendTraceLog traceLog(cx, TraceLogger_BytecodeEmission, parser->errorReporter(), funbox);
+
+    setScriptStartOffsetIfUnset(body->pn_pos);
 
     // The ordering of these EmitterScopes is important. The named lambda
     // scope needs to enclose the function scope needs to enclose the extra
     // var scope.
 
     Maybe<EmitterScope> namedLambdaEmitterScope;
     if (funbox->namedLambdaBindings()) {
         namedLambdaEmitterScope.emplace(this);
@@ -4978,25 +4946,17 @@ BytecodeEmitter::emitFunctionScript(Pars
         if (!namedLambdaEmitterScope->leave(this))
             return false;
         namedLambdaEmitterScope.reset();
     }
 
     if (!JSScript::fullyInitFromEmitter(cx, script, this))
         return false;
 
-    // URL and source map information must be set before firing
-    // Debugger::onNewScript. Only top-level functions need this, as compiling
-    // the outer scripts of nested functions already processed the source.
-    if (emitterMode != LazyFunction && !parent) {
-        if (!maybeSetDisplayURL() || !maybeSetSourceMap())
-            return false;
-
-        tellDebuggerAboutCompiledScript(cx);
-    }
+    tellDebuggerAboutCompiledScript(cx);
 
     return true;
 }
 
 template <typename NameEmitter>
 bool
 BytecodeEmitter::emitDestructuringDeclsWithEmitter(ParseNode* pattern, NameEmitter emitName)
 {
@@ -6578,42 +6538,42 @@ BytecodeEmitter::emitSingletonInitialise
         (pn->getKind() == ParseNodeKind::Object) ? SingletonObject : TenuredObject;
 
     RootedValue value(cx);
     if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value, nullptr, 0, newKind))
         return false;
 
     MOZ_ASSERT_IF(newKind == SingletonObject, value.toObject().isSingleton());
 
-    ObjectBox* objbox = parser.newObjectBox(&value.toObject());
+    ObjectBox* objbox = parser->newObjectBox(&value.toObject());
     if (!objbox)
         return false;
 
     return emitObjectOp(objbox, JSOP_OBJECT);
 }
 
 bool
 BytecodeEmitter::emitCallSiteObject(ParseNode* pn)
 {
     RootedValue value(cx);
     if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value))
         return false;
 
     MOZ_ASSERT(value.isObject());
 
-    ObjectBox* objbox1 = parser.newObjectBox(&value.toObject());
+    ObjectBox* objbox1 = parser->newObjectBox(&value.toObject());
     if (!objbox1)
         return false;
 
     if (!pn->as<CallSiteNode>().getRawArrayValue(cx, &value))
         return false;
 
     MOZ_ASSERT(value.isObject());
 
-    ObjectBox* objbox2 = parser.newObjectBox(&value.toObject());
+    ObjectBox* objbox2 = parser->newObjectBox(&value.toObject());
     if (!objbox2)
         return false;
 
     return emitObjectPairOp(objbox1, objbox2, JSOP_CALLSITEOBJ);
 }
 
 /* See the SRC_FOR source note offsetBias comments later in this file. */
 JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
@@ -7118,30 +7078,30 @@ BytecodeEmitter::emitInitializeForInOrOf
                "must have a per-iteration value for initializing");
 
     ParseNode* target = forHead->pn_kid1;
     MOZ_ASSERT(!forHead->pn_kid2);
 
     // If the for-in/of loop didn't have a variable declaration, per-loop
     // initialization is just assigning the iteration value to a target
     // expression.
-    if (!parser.isDeclarationList(target))
+    if (!parser->astGenerator().isDeclarationList(target))
         return emitAssignment(target, ParseNodeKind::Assign, nullptr); // ... ITERVAL
 
     // Otherwise, per-loop initialization is (possibly) declaration
     // initialization.  If the declaration is a lexical declaration, it must be
     // initialized.  If the declaration is a variable declaration, an
     // assignment to that name (which does *not* necessarily assign to the
     // variable!) must be generated.
 
     if (!updateSourceCoordNotes(target->pn_pos.begin))
         return false;
 
     MOZ_ASSERT(target->isForLoopDeclaration());
-    target = parser.singleBindingFromDeclaration(target);
+    target = parser->astGenerator().singleBindingFromDeclaration(target);
 
     if (target->isKind(ParseNodeKind::Name)) {
         auto emitSwapScopeAndRhs = [](BytecodeEmitter* bce, const NameLocation&,
                                       bool emittedBindOp)
         {
             if (emittedBindOp) {
                 // Per-iteration initialization in for-in/of loops computes the
                 // iteration value *before* initializing.  Thus the
@@ -7371,18 +7331,18 @@ BytecodeEmitter::emitForIn(ParseNode* fo
 
     ParseNode* forInHead = forInLoop->pn_left;
     MOZ_ASSERT(forInHead->isKind(ParseNodeKind::ForIn));
     MOZ_ASSERT(forInHead->isArity(PN_TERNARY));
 
     // Annex B: Evaluate the var-initializer expression if present.
     // |for (var i = initializer in expr) { ... }|
     ParseNode* forInTarget = forInHead->pn_kid1;
-    if (parser.isDeclarationList(forInTarget)) {
-        ParseNode* decl = parser.singleBindingFromDeclaration(forInTarget);
+    if (parser->astGenerator().isDeclarationList(forInTarget)) {
+        ParseNode* decl = parser->astGenerator().singleBindingFromDeclaration(forInTarget);
         if (decl->isKind(ParseNodeKind::Name)) {
             if (ParseNode* initializer = decl->expr()) {
                 MOZ_ASSERT(forInTarget->isKind(ParseNodeKind::Var),
                            "for-in initializers are only permitted for |var| declarations");
 
                 if (!updateSourceCoordNotes(decl->pn_pos.begin))
                     return false;
 
@@ -7643,17 +7603,17 @@ BytecodeEmitter::emitCStyleFor(ParseNode
         if (!updateSourceCoordNotes(update->pn_pos.begin))
             return false;
         if (!emitTree(update, ValueUsage::IgnoreValue))
             return false;
         if (!emit1(JSOP_POP))
             return false;
 
         /* Restore the absolute line number for source note readers. */
-        uint32_t lineNum = parser.tokenStream().srcCoords.lineNum(pn->pn_pos.end);
+        uint32_t lineNum = parser->errorReporter().lineAt(pn->pn_pos.end);
         if (currentLine() != lineNum) {
             if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum)))
                 return false;
             current->currentLine = lineNum;
             current->lastColumn = 0;
         }
     }
 
@@ -7799,18 +7759,18 @@ BytecodeEmitter::emitFunction(ParseNode*
             if (emittingRunOnceLambda)
                 fun->lazyScript()->setTreatAsRunOnce();
         } else {
             MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript);
 
             // Inherit most things (principals, version, etc) from the
             // parent.  Use default values for the rest.
             Rooted<JSScript*> parent(cx, script);
-            MOZ_ASSERT(parent->mutedErrors() == parser.options().mutedErrors());
-            const TransitiveCompileOptions& transitiveOptions = parser.options();
+            MOZ_ASSERT(parent->mutedErrors() == parser->options().mutedErrors());
+            const TransitiveCompileOptions& transitiveOptions = parser->options();
             CompileOptions options(cx, transitiveOptions);
 
             Rooted<JSObject*> sourceObject(cx, script->sourceObject());
             Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
                                                           funbox->bufStart, funbox->bufEnd,
                                                           funbox->toStringStart,
                                                           funbox->toStringEnd));
             if (!script)
@@ -8085,18 +8045,18 @@ BytecodeEmitter::emitWhile(ParseNode* pn
     // If we have a single-line while, like "while (x) ;", we want to
     // emit the line note before the initial goto, so that the
     // debugger sees a single entry point.  This way, if there is a
     // breakpoint on the line, it will only fire once; and "next"ing
     // will skip the whole loop.  However, for the multi-line case we
     // want to emit the line note after the initial goto, so that
     // "cont" stops on each iteration -- but without a stop before the
     // first iteration.
-    if (parser.tokenStream().srcCoords.lineNum(pn->pn_pos.begin) ==
-        parser.tokenStream().srcCoords.lineNum(pn->pn_pos.end))
+    if (parser->errorReporter().lineAt(pn->pn_pos.begin) ==
+        parser->errorReporter().lineAt(pn->pn_pos.end))
     {
         if (!updateSourceCoordNotes(pn->pn_pos.begin))
             return false;
     }
 
     JumpTarget top{ -1 };
     if (!emitJumpTarget(&top))
         return false;
@@ -9175,17 +9135,17 @@ BytecodeEmitter::emitCallee(ParseNode* c
         } else {
             if (!emitTree(callee))
                 return false;
         }
         *callop = false;
         break;
       case ParseNodeKind::SuperBase:
         MOZ_ASSERT(call->isKind(ParseNodeKind::SuperCall));
-        MOZ_ASSERT(parser.isSuperBase(callee));
+        MOZ_ASSERT(parser->astGenerator().isSuperBase(callee));
         if (!emit1(JSOP_SUPERFUN))
             return false;
         break;
       default:
         if (!emitTree(callee))
             return false;
         *callop = false;             /* trigger JSOP_UNDEFINED after */
         break;
@@ -9246,17 +9206,17 @@ BytecodeEmitter::emitCallOrNew(ParseNode
      * Then (or in a call case that has no explicit reference-base
      * object) we emit JSOP_UNDEFINED to produce the undefined |this|
      * value required for calls (which non-strict mode functions
      * will box into the global object).
      */
     uint32_t argc = pn->pn_count - 1;
 
     if (argc >= ARGC_LIMIT) {
-        parser.reportError(callop ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS);
+        reportError(pn, callop ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS);
         return false;
     }
 
     ParseNode* pn2 = pn->pn_head;
     bool spread = JOF_OPTYPE(pn->getOp()) == JOF_BYTE;
 
     if (pn2->isKind(ParseNodeKind::Name) && emitterMode == BytecodeEmitter::SelfHosting && !spread) {
         // Calls to "forceInterpreter", "callFunction",
@@ -9390,17 +9350,17 @@ BytecodeEmitter::emitCallOrNew(ParseNode
             return false;
         checkTypeSet(pn->getOp());
     }
     if (pn->isOp(JSOP_EVAL) ||
         pn->isOp(JSOP_STRICTEVAL) ||
         pn->isOp(JSOP_SPREADEVAL) ||
         pn->isOp(JSOP_STRICTSPREADEVAL))
     {
-        uint32_t lineNum = parser.tokenStream().srcCoords.lineNum(pn->pn_pos.begin);
+        uint32_t lineNum = parser->errorReporter().lineAt(pn->pn_pos.begin);
         if (!emitUint32Operand(JSOP_LINENO, lineNum))
             return false;
     }
 
     return true;
 }
 
 static const JSOp ParseNodeKindToJSOp[] = {
@@ -9830,17 +9790,17 @@ BytecodeEmitter::emitObject(ParseNode* p
     }
 
     return true;
 }
 
 bool
 BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset)
 {
-    ObjectBox* objbox = parser.newObjectBox(obj);
+    ObjectBox* objbox = parser->newObjectBox(obj);
     if (!objbox)
         return false;
 
     static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
                   "newinit and newobject must have equal length to edit in-place");
 
     uint32_t index = objectList.add(objbox);
     jsbytecode* code = this->code(offset);
@@ -9879,17 +9839,17 @@ BytecodeEmitter::emitArrayLiteral(ParseN
                 // use ObjectGroup::getOrFixupCopyOnWriteObject to make sure the
                 // group for the template is accurate. We don't do this here as we
                 // want to use ObjectGroup::allocationSiteGroup, which requires a
                 // finished script.
                 JSObject* obj = &value.toObject();
                 MOZ_ASSERT(obj->is<ArrayObject>() &&
                            obj->as<ArrayObject>().denseElementsAreCopyOnWrite());
 
-                ObjectBox* objbox = parser.newObjectBox(obj);
+                ObjectBox* objbox = parser->newObjectBox(obj);
                 if (!objbox)
                     return false;
 
                 return emitObjectOp(objbox, JSOP_NEWARRAY_COPYONWRITE);
             }
         }
     }
 
@@ -11119,17 +11079,17 @@ BytecodeEmitter::addToSrcNoteDelta(jssrc
     }
     return true;
 }
 
 bool
 BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offset)
 {
     if (!SN_REPRESENTABLE_OFFSET(offset)) {
-        parser.reportError(JSMSG_NEED_DIET, js_script_str);
+        reportError(nullptr, JSMSG_NEED_DIET, js_script_str);
         return false;
     }
 
     SrcNotesVector& notes = this->notes();
 
     /* Find the offset numbered which (i.e., skip exactly which offsets). */
     jssrcnote* sn = &notes[index];
     MOZ_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -7,16 +7,17 @@
 /* JS bytecode generation. */
 
 #ifndef frontend_BytecodeEmitter_h
 #define frontend_BytecodeEmitter_h
 
 #include "mozilla/Attributes.h"
 
 #include "ds/InlineTable.h"
+#include "frontend/BCEParserHandle.h"
 #include "frontend/EitherParser.h"
 #include "frontend/SharedContext.h"
 #include "frontend/SourceNotes.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/Interpreter.h"
 #include "vm/Iteration.h"
 #include "vm/JSContext.h"
 #include "vm/JSScript.h"
@@ -215,17 +216,20 @@ struct MOZ_STACK_CLASS BytecodeEmitter
 
         EmitSection(JSContext* cx, uint32_t lineNum)
           : code(cx), notes(cx), lastNoteOffset(0), currentLine(lineNum), lastColumn(0),
             lastTarget{ -1 - ptrdiff_t(JSOP_JUMPTARGET_LENGTH) }
         {}
     };
     EmitSection prologue, main, *current;
 
-    EitherParser<FullParseHandler> parser;
+    // Private storage for parser wrapper. DO NOT REFERENCE INTERNALLY. May not be initialized.
+    // Use |parser| instead.
+    mozilla::Maybe<EitherParser> ep_;
+    BCEParserHandle *parser;
 
     PooledMapPtr<AtomIndexMap> atomIndices; /* literals indexed for mapping */
     unsigned        firstLine;      /* first line, for JSScript::initFromEmitter */
 
     uint32_t        maxFixedSlots;  /* maximum number of fixed frame slots so far */
     uint32_t        maxStackDepth;  /* maximum number of expression stack slots so far */
 
     int32_t         stackDepth;     /* current stack depth in script frame */
@@ -276,50 +280,82 @@ struct MOZ_STACK_CLASS BytecodeEmitter
          * Check the static scope chain of the root function for resolving free
          * variable accesses in the script.
          */
         LazyFunction
     };
 
     const EmitterMode emitterMode;
 
+    MOZ_INIT_OUTSIDE_CTOR uint32_t scriptStartOffset;
+    bool scriptStartOffsetSet;
+
     // The end location of a function body that is being emitted.
     MOZ_INIT_OUTSIDE_CTOR uint32_t functionBodyEndPos;
     // Whether functionBodyEndPos was set.
     bool functionBodyEndPosSet;
 
     /*
      * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
      * space above their tempMark points. This means that you cannot alloc from
      * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
      * destruction.
      */
-    BytecodeEmitter(BytecodeEmitter* parent, const EitherParser<FullParseHandler>& parser,
-                    SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
-                    uint32_t lineNum, EmitterMode emitterMode = Normal);
+  private:
+    // Internal constructor, for delegation use only.
+    BytecodeEmitter(BytecodeEmitter* parent, SharedContext* sc, HandleScript script,
+                    Handle<LazyScript*> lazyScript, uint32_t lineNum, EmitterMode emitterMode);
+
+    void initFromBodyPosition(TokenPos bodyPosition);
+
+  public:
+
+    BytecodeEmitter(BytecodeEmitter* parent, BCEParserHandle* parser, SharedContext* sc,
+                    HandleScript script, Handle<LazyScript*> lazyScript, uint32_t lineNum,
+                    EmitterMode emitterMode = Normal);
+
+    BytecodeEmitter(BytecodeEmitter* parent, const EitherParser& parser, SharedContext* sc,
+                    HandleScript script, Handle<LazyScript*> lazyScript, uint32_t lineNum,
+                    EmitterMode emitterMode = Normal);
 
     template<typename CharT>
     BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, CharT>* parser,
                     SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
                     uint32_t lineNum, EmitterMode emitterMode = Normal)
-      : BytecodeEmitter(parent, EitherParser<FullParseHandler>(parser), sc, script, lazyScript,
+      : BytecodeEmitter(parent, EitherParser(parser), sc, script, lazyScript,
                         lineNum, emitterMode)
     {}
 
     // An alternate constructor that uses a TokenPos for the starting
     // line and that sets functionBodyEndPos as well.
-    BytecodeEmitter(BytecodeEmitter* parent, const EitherParser<FullParseHandler>& parser,
-                    SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
-                    TokenPos bodyPosition, EmitterMode emitterMode = Normal);
+    BytecodeEmitter(BytecodeEmitter* parent, BCEParserHandle* parser, SharedContext* sc,
+                    HandleScript script, Handle<LazyScript*> lazyScript, TokenPos bodyPosition,
+                    EmitterMode emitterMode = Normal)
+        : BytecodeEmitter(parent, parser, sc, script, lazyScript,
+                          parser->errorReporter().lineAt(bodyPosition.begin),
+                          emitterMode)
+    {
+        initFromBodyPosition(bodyPosition);
+    }
+
+    BytecodeEmitter(BytecodeEmitter* parent, const EitherParser& parser, SharedContext* sc,
+                    HandleScript script, Handle<LazyScript*> lazyScript, TokenPos bodyPosition,
+                    EmitterMode emitterMode = Normal)
+        : BytecodeEmitter(parent, parser, sc, script, lazyScript,
+                          parser.errorReporter().lineAt(bodyPosition.begin),
+                          emitterMode)
+    {
+        initFromBodyPosition(bodyPosition);
+    }
 
     template<typename CharT>
     BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler, CharT>* parser,
                     SharedContext* sc, HandleScript script, Handle<LazyScript*> lazyScript,
                     TokenPos bodyPosition, EmitterMode emitterMode = Normal)
-      : BytecodeEmitter(parent, EitherParser<FullParseHandler>(parser), sc, script, lazyScript,
+      : BytecodeEmitter(parent, EitherParser(parser), sc, script, lazyScript,
                         bodyPosition, emitterMode)
     {}
 
     MOZ_MUST_USE bool init();
 
     template <typename Predicate /* (NestableControl*) -> bool */>
     NestableControl* findInnermostNestableControl(Predicate predicate) const;
 
@@ -376,22 +412,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter
     MOZ_MUST_USE bool checkSingletonContext();
 
     // Check whether our function is in a run-once context (a toplevel
     // run-one script or a run-once lambda).
     MOZ_MUST_USE bool checkRunOnceContext();
 
     bool needsImplicitThis();
 
-    MOZ_MUST_USE bool maybeSetDisplayURL();
-    MOZ_MUST_USE bool maybeSetSourceMap();
     void tellDebuggerAboutCompiledScript(JSContext* cx);
 
-    inline TokenStreamAnyChars& tokenStream();
-
     BytecodeVector& code() const { return current->code; }
     jsbytecode* code(ptrdiff_t offset) const { return current->code.begin() + offset; }
     ptrdiff_t offset() const { return current->code.end() - current->code.begin(); }
     ptrdiff_t prologueOffset() const { return prologue.code.end() - prologue.code.begin(); }
     void switchToMain() { current = &main; }
     void switchToPrologue() { current = &prologue; }
     bool inPrologue() const { return current == &prologue; }
 
@@ -412,16 +444,23 @@ struct MOZ_STACK_CLASS BytecodeEmitter
         return lastOpcodeIsJumpTarget() ? current->lastTarget.offset : offset();
     }
 
     void setFunctionBodyEndPos(TokenPos pos) {
         functionBodyEndPos = pos.end;
         functionBodyEndPosSet = true;
     }
 
+    void setScriptStartOffsetIfUnset(TokenPos pos) {
+        if (!scriptStartOffsetSet) {
+            scriptStartOffset = pos.begin;
+            scriptStartOffsetSet = true;
+        }
+    }
+
     void reportError(ParseNode* pn, unsigned errorNumber, ...);
     bool reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...);
 
     // If pn contains a useful expression, return true with *answer set to true.
     // If pn contains a useless expression, return true with *answer set to
     // false. Return false on error.
     //
     // The caller should initialize *answer to false and invoke this function on
--- a/js/src/frontend/EitherParser.h
+++ b/js/src/frontend/EitherParser.h
@@ -15,16 +15,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/Move.h"
 #include "mozilla/Tuple.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Variant.h"
 
 #include <utility>
 
+#include "frontend/BCEParserHandle.h"
 #include "frontend/Parser.h"
 #include "frontend/TokenStream.h"
 
 namespace js {
 
 namespace detail {
 
 template<template <class Parser> class GetThis,
@@ -63,24 +64,16 @@ struct InvokeMemberFunction
 
 template<class Parser>
 struct GetParser
 {
     static Parser* get(Parser* parser) { return parser; }
 };
 
 template<class Parser>
-struct GetParseHandler
-{
-    static auto get(Parser* parser) -> decltype(&parser->handler) {
-        return &parser->handler;
-    }
-};
-
-template<class Parser>
 struct GetTokenStream
 {
     static auto get(Parser* parser) -> decltype(&parser->tokenStream) {
         return &parser->tokenStream;
     }
 };
 
 // Member function-computing templates.
@@ -88,187 +81,92 @@ struct GetTokenStream
 template<class Parser>
 struct ParserOptions
 {
     static constexpr auto get() -> decltype(&Parser::options) {
         return &Parser::options;
     }
 };
 
-template<class TokenStream>
-struct TokenStreamComputeErrorMetadata
-{
-    static constexpr auto get() -> decltype(&TokenStream::computeErrorMetadata) {
-        return &TokenStream::computeErrorMetadata;
-    }
-};
-
 template<class Parser>
 struct ParserNewObjectBox
 {
     static constexpr auto get() -> decltype(&Parser::newObjectBox) {
         return &Parser::newObjectBox;
     }
 };
 
-template<class Handler>
-struct HandlerSingleBindingFromDeclaration
-{
-    static constexpr auto get() -> decltype(&Handler::singleBindingFromDeclaration) {
-        return &Handler::singleBindingFromDeclaration;
-    }
-};
-
-template<class Handler>
-struct HandlerIsDeclarationList
-{
-    static constexpr auto get() -> decltype(&Handler::isDeclarationList) {
-        return &Handler::isDeclarationList;
-    }
-};
-
-template<class Handler>
-struct HandlerIsSuperBase
-{
-    static constexpr auto get() -> decltype(&Handler::isSuperBase) {
-        return &Handler::isSuperBase;
-    }
-};
-
-template<class TokenStream>
-struct TokenStreamReportError
-{
-    static constexpr auto get() -> decltype(&TokenStream::reportError) {
-        return &TokenStream::reportError;
-    }
-};
-
-template<class TokenStream>
-struct TokenStreamReportExtraWarning
-{
-    static constexpr auto get() -> decltype(&TokenStream::reportExtraWarningErrorNumberVA) {
-        return &TokenStream::reportExtraWarningErrorNumberVA;
-    }
-};
-
 // Generic matchers.