Merge mozilla-central to autoland.
authorCosmin Sabou <csabou@mozilla.com>
Fri, 15 Feb 2019 20:50:34 +0200
changeset 517462 7465be2b8821fe89f5bbf1df01e07d2d81f25568
parent 517461 79d9076cbaa1c24ca96094e86706952951bb67f6 (current diff)
parent 517425 8961019ee4c6fe27e6319d9cf9ea6867b4f3c7bb (diff)
child 517463 977d3cf4a200f3690222f6423b50a9a3cf276673
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone67.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.
browser/app/profile/firefox.js
browser/components/build/nsModule.cpp
browser/components/migration/360seProfileMigrator.js
browser/components/migration/BrowserProfileMigrators.manifest
browser/components/migration/ChromeProfileMigrator.js
browser/components/migration/EdgeProfileMigrator.js
browser/components/migration/FirefoxProfileMigrator.js
browser/components/migration/IEProfileMigrator.js
browser/components/migration/ProfileMigrator.js
browser/components/migration/SafariProfileMigrator.js
browser/components/newtab/NewTabComponents.manifest
browser/components/newtab/aboutNewTabService.js
browser/components/nsBrowserContentHandler.js
browser/components/nsBrowserGlue.js
browser/components/payments/paymentUIService.js
browser/components/payments/payments.manifest
browser/components/protocolhandler/WebProtocolHandlerRegistrar.js
browser/extensions/pdfjs/pdfjs.manifest
devtools/startup/aboutdebugging-new-registration.js
devtools/startup/aboutdebugging-new.manifest
devtools/startup/aboutdebugging-registration.js
devtools/startup/aboutdebugging.manifest
devtools/startup/aboutdevtools/aboutdevtools-registration.js
devtools/startup/aboutdevtools/aboutdevtools.manifest
devtools/startup/aboutdevtoolstoolbox-registration.js
devtools/startup/aboutdevtoolstoolbox.manifest
devtools/startup/devtools-startup.js
devtools/startup/devtools-startup.manifest
dom/base/ProcessSelector.js
dom/base/ProcessSelector.manifest
dom/base/SlowScriptDebug.js
dom/base/SlowScriptDebug.manifest
dom/base/contentAreaDropListener.js
dom/base/contentAreaDropListener.manifest
dom/browser-element/BrowserElementParent.js
dom/browser-element/BrowserElementParent.manifest
dom/console/ConsoleAPI.manifest
dom/console/ConsoleAPIStorage.js
dom/html/htmlMenuBuilder.js
dom/html/htmlMenuBuilder.manifest
dom/media/PeerConnection.js
dom/media/PeerConnection.manifest
dom/notification/NotificationStorage.js
dom/notification/NotificationStorage.manifest
dom/payments/PaymentRequestModule.cpp
dom/presentation/PresentationDataChannelSessionTransport.js
dom/presentation/PresentationDataChannelSessionTransport.manifest
dom/presentation/PresentationNetworkHelper.js
dom/presentation/PresentationNetworkHelper.manifest
dom/presentation/provider/AndroidCastDeviceProvider.js
dom/presentation/provider/AndroidCastDeviceProvider.manifest
dom/presentation/provider/BuiltinProviders.manifest
dom/presentation/provider/PresentationControlService.js
dom/push/Push.js
dom/push/PushComponents.js
dom/svg/SVGAngle.cpp
dom/svg/SVGAngle.h
dom/system/NetworkGeolocationProvider.js
dom/system/NetworkGeolocationProvider.manifest
image/decoders/icon/nsIconModule.cpp
intl/build/nsI18nModule.cpp
intl/uconv/nsUConvModule.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
layout/tools/recording/recording-cmdline.js
layout/tools/recording/recording-cmdline.manifest
modules/libjar/nsJARFactory.cpp
modules/libjar/zipwriter/ZipWriterModule.cpp
netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js
netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.manifest
netwerk/protocol/http/UAOverridesBootstrapper.js
netwerk/protocol/http/UAOverridesBootstrapper.manifest
netwerk/protocol/http/WellKnownOpportunisticUtils.js
netwerk/protocol/http/WellKnownOpportunisticUtils.manifest
netwerk/test/unit/test_crossOriginOpenerPolicy.js
netwerk/test/unit_ipc/test_crossOriginOpenerPolicy_wrap.js
old-configure.in
services/fxaccounts/FxAccountsComponents.manifest
services/fxaccounts/FxAccountsPush.js
services/settings/RemoteSettingsComponents.js
services/sync/Weave.js
toolkit/components/asyncshutdown/nsAsyncShutdown.js
toolkit/components/asyncshutdown/nsAsyncShutdown.manifest
toolkit/components/backgroundhangmonitor/BHRTelemetryService.js
toolkit/components/backgroundhangmonitor/BHRTelemetryService.manifest
toolkit/components/browser/build/nsWebBrowserModule.cpp
toolkit/components/captivedetect/CaptivePortalDetectComponents.manifest
toolkit/components/captivedetect/captivedetect.js
toolkit/components/cleardata/ClearDataService.js
toolkit/components/cleardata/ClearDataService.manifest
toolkit/components/contentprefs/ContentPrefService2.js
toolkit/components/contentprefs/ContentPrefService2.manifest
toolkit/components/crashes/CrashService.js
toolkit/components/crashes/CrashService.manifest
toolkit/components/crashmonitor/crashmonitor.manifest
toolkit/components/crashmonitor/nsCrashMonitor.js
toolkit/components/downloads/DownloadLegacy.js
toolkit/components/downloads/Downloads.manifest
toolkit/components/gfx/GfxSanityTest.manifest
toolkit/components/gfx/SanityTest.js
toolkit/components/mediasniffer/nsMediaSnifferModule.cpp
toolkit/components/mozintl/mozIntl.js
toolkit/components/mozintl/mozIntl.manifest
toolkit/components/mozprotocol/mozProtocolHandler.js
toolkit/components/mozprotocol/mozProtocolHandler.manifest
toolkit/components/normandy/shield-content-process.js
toolkit/components/normandy/shield.manifest
toolkit/components/nsDefaultCLH.js
toolkit/components/nsDefaultCLH.manifest
toolkit/components/passwordmgr/nsLoginInfo.js
toolkit/components/passwordmgr/nsLoginManager.js
toolkit/components/passwordmgr/nsLoginManagerPrompter.js
toolkit/components/passwordmgr/passwordmgr.manifest
toolkit/components/places/ColorAnalyzer.js
toolkit/components/places/PageIconProtocolHandler.js
toolkit/components/places/PlacesCategoriesStarter.js
toolkit/components/places/UnifiedComplete.js
toolkit/components/places/nsPlacesExpiration.js
toolkit/components/places/nsPlacesModule.cpp
toolkit/components/places/nsTaggingService.js
toolkit/components/places/toolkitplaces.manifest
toolkit/components/processsingleton/ContentProcessSingleton.js
toolkit/components/processsingleton/MainProcessSingleton.js
toolkit/components/prompts/src/nsPrompter.js
toolkit/components/prompts/src/nsPrompter.manifest
toolkit/components/remotebrowserutils/RemoteWebNavigation.js
toolkit/components/remotebrowserutils/remotebrowserutils.manifest
toolkit/components/remotebrowserutils/tests/browser/browser_httpCrossOriginOpenerPolicy.js
toolkit/components/remotebrowserutils/tests/browser/browser_httpToFileHistory.js
toolkit/components/remotebrowserutils/tests/browser/coop_header.sjs
toolkit/components/remotebrowserutils/tests/browser/head.js
toolkit/components/satchel/FormHistoryStartup.js
toolkit/components/satchel/nsFormAutoComplete.js
toolkit/components/satchel/nsInputListAutoComplete.js
toolkit/components/satchel/satchel.manifest
toolkit/components/search/nsSearchService.js
toolkit/components/search/nsSearchSuggestions.js
toolkit/components/search/nsSidebar.js
toolkit/components/telemetry/TelemetryStartup.js
toolkit/components/telemetry/TelemetryStartup.manifest
toolkit/components/terminator/nsTerminatorTelemetry.js
toolkit/components/thumbnails/PageThumbsComponents.manifest
toolkit/components/thumbnails/PageThumbsStorageService.js
toolkit/components/thumbnails/nsPageThumbsModule.cpp
toolkit/components/timermanager/nsUpdateTimerManager.js
toolkit/components/timermanager/nsUpdateTimerManager.manifest
toolkit/components/tooltiptext/TooltipTextProvider.js
toolkit/components/tooltiptext/TooltipTextProvider.manifest
toolkit/components/url-classifier/nsURLClassifier.manifest
toolkit/components/url-classifier/nsUrlClassifierHashCompleter.js
toolkit/components/url-classifier/nsUrlClassifierLib.js
toolkit/components/url-classifier/nsUrlClassifierListManager.js
toolkit/components/urlformatter/nsURLFormatter.js
toolkit/components/urlformatter/nsURLFormatter.manifest
toolkit/components/utils/simpleServices.js
toolkit/components/utils/utils.manifest
toolkit/components/xulstore/XULStore.js
toolkit/components/xulstore/XULStore.manifest
toolkit/content/customElements.js
toolkit/content/widgets/popupnotification.js
toolkit/mozapps/downloads/nsHelperAppDlg.js
toolkit/mozapps/downloads/nsHelperAppDlg.manifest
toolkit/mozapps/extensions/amContentHandler.js
toolkit/mozapps/extensions/amInstallTrigger.js
toolkit/mozapps/extensions/amWebAPI.js
toolkit/mozapps/handling/nsContentDispatchChooser.js
toolkit/mozapps/handling/nsContentDispatchChooser.manifest
toolkit/mozapps/update/nsUpdateService.js
toolkit/mozapps/update/nsUpdateServiceStub.js
uriloader/exthandler/nsWebHandlerApp.js
uriloader/exthandler/nsWebHandlerApp.manifest
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Merge day clobber
\ No newline at end of file
+Bug 1524688: Deleting preprocessed manifests requires clobber.
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,9 +1,11 @@
-[[package]]
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
 name = "Inflector"
 version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
--- a/accessible/tests/mochitest/hyperlink/test_general.xul
+++ b/accessible/tests/mochitest/hyperlink/test_general.xul
@@ -22,24 +22,24 @@
           src="hyperlink.js" />
 
   <script type="application/javascript">
   <![CDATA[
     function testThis(aID, aAcc, aRole, aAnchorCount, aAnchorName, aURI,
                       aStartIndex, aEndIndex, aValid)
     {
       testRole(aID, aRole);
-      is(aAcc.anchorCount, aAnchorCount, "Wrong number of anchors for ID " 
+      is(aAcc.anchorCount, aAnchorCount, "Wrong number of anchors for ID "
          + aID + "!");
       is(aAcc.getAnchor(0).name, aAnchorName, "Wrong name for ID " + aID + "!");
       is(aAcc.getURI(0).spec, aURI, "URI wrong for ID " + aID + "!");
-      is(aAcc.startIndex, aStartIndex, "Wrong startIndex value for ID " + aID 
+      is(aAcc.startIndex, aStartIndex, "Wrong startIndex value for ID " + aID
          + "!");
       is(aAcc.endIndex, aEndIndex, "Wrong endIndex value for ID " + aID + "!");
-      is(aAcc.valid, aValid, "Wrong valid state for ID " + aID + "!");      
+      is(aAcc.valid, aValid, "Wrong valid state for ID " + aID + "!");
     }
 
     var gQueue = null;
     function doTest()
     {
       var linkedLabelAcc = getAccessible("linkedLabel",
                                          [nsIAccessibleHyperLink]);
       testThis("linkedLabel", linkedLabelAcc, ROLE_LINK, 1,
@@ -84,14 +84,14 @@
     </a>
     <p id="display"></p>
     <div id="content" style="display: none">
     </div>
     <pre id="test">
     </pre>
   </body>
 
-  <label id="linkedLabel" class="text-link" href="http://www.mozilla.org/">
+  <label id="linkedLabel" href="http://www.mozilla.org/" is="text-link">
     Mozilla Foundation home</label>
-  <label id="linkLabelWithValue" value="Mozilla Foundation" class="text-link"
+  <label id="linkLabelWithValue" value="Mozilla Foundation" is="text-link"
    href="http://www.mozilla.org/" />
   <label id="normalLabel" value="This label should not be a link" />
 </window>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -478,19 +478,16 @@ pref("browser.tabs.delayHidingAudioPlayi
 // New, experimental, tab open/close animations.
 pref("browser.tabs.newanimations", false);
 
 // Pref to control whether we use separate privileged content processes.
 #if defined(NIGHTLY_BUILD) && !defined(MOZ_ASAN)
 pref("browser.tabs.remote.separatePrivilegedContentProcess", true);
 #endif
 
-// Turn on HTTP response process selection.
-pref("browser.tabs.remote.useHTTPResponseProcessSelection", true);
-
 pref("browser.ctrlTab.recentlyUsedOrder", true);
 
 // By default, do not export HTML at shutdown.
 // If true, at shutdown the bookmarks in your menu and toolbar will
 // be exported as HTML to the bookmarks.html file.
 pref("browser.bookmarks.autoExportHTML",          false);
 
 // The maximum number of daily bookmark backups to
--- a/browser/base/content/aboutDialog.xul
+++ b/browser/base/content/aboutDialog.xul
@@ -49,17 +49,17 @@
       <vbox id="leftBox" flex="1"/>
       <vbox id="rightBox" flex="1">
         <label id="release" hidden="true">
         <!-- This string is explicitly not translated -->
           Extended Support Release
         </label>
         <hbox align="baseline">
           <label id="version"/>
-          <label id="releasenotes" class="text-link" hidden="true" data-l10n-id="releaseNotes-link"></label>
+          <label id="releasenotes" is="text-link" hidden="true" data-l10n-id="releaseNotes-link"></label>
         </hbox>
 
         <label id="distribution" class="text-blurb"/>
         <label id="distributionId" class="text-blurb"/>
 
         <vbox id="detailsBox">
           <vbox id="updateBox">
 #ifdef MOZ_UPDATER
@@ -90,32 +90,32 @@
                 <html:img class="update-throbber" src="chrome://global/skin/icons/loading.png" data-l10n-name="icon"/>
                 <label id="downloadStatus" data-l10n-name="download-status"/>
               </hbox>
               <hbox id="applying" align="center">
                 <image class="update-throbber"/>
                 <label data-l10n-id="update-applying"></label>
               </hbox>
               <hbox id="downloadFailed" align="center" data-l10n-id="update-failed">
-                <label id="failedLink" class="text-link" data-l10n-name="failed-link"></label>
+                <label id="failedLink" is="text-link" data-l10n-name="failed-link"></label>
               </hbox>
               <hbox id="policyDisabled" align="center">
                 <label data-l10n-id="update-adminDisabled"></label>
               </hbox>
               <hbox id="noUpdatesFound" align="center">
                 <label data-l10n-id="update-noUpdatesFound"></label>
               </hbox>
               <hbox id="otherInstanceHandlingUpdates" align="center">
                 <label data-l10n-id="update-otherInstanceHandlingUpdates"></label>
               </hbox>
               <hbox id="manualUpdate" align="center" data-l10n-id="update-manual">
-                <label id="manualLink" class="text-link" data-l10n-name="manual-link"/>
+                <label id="manualLink" is="text-link" data-l10n-name="manual-link"/>
               </hbox>
               <hbox id="unsupportedSystem" align="center" data-l10n-id="update-unsupported">
-                <label id="unsupportedLink" class="text-link" data-l10n-name="unsupported-link"></label>
+                <label id="unsupportedLink" is="text-link" data-l10n-name="unsupported-link"></label>
               </hbox>
               <hbox id="restarting" align="center">
                 <image class="update-throbber"/>
                 <label data-l10n-id="update-restarting"></label>
               </hbox>
             </deck>
 #endif
           </vbox>
@@ -123,36 +123,36 @@
 #ifdef MOZ_UPDATER
           <description class="text-blurb" id="currentChannelText" data-l10n-id="channel-description">
             <label id="currentChannel" data-l10n-name="current-channel"></label>
           </description>
 #endif
           <vbox id="experimental" hidden="true">
             <description class="text-blurb" id="warningDesc" data-l10n-id="warningDesc-version"></description>
             <description class="text-blurb" id="communityExperimentalDesc" data-l10n-id="community-exp">
-              <label class="text-link" href="http://www.mozilla.org/" data-l10n-name="community-exp-mozillaLink"></label>
-              <label class="text-link" useoriginprincipal="true" href="about:credits" data-l10n-name="community-exp-creditsLink"></label>
+              <label is="text-link" href="http://www.mozilla.org/" data-l10n-name="community-exp-mozillaLink"></label>
+              <label is="text-link" useoriginprincipal="true" href="about:credits" data-l10n-name="community-exp-creditsLink"></label>
             </description>
           </vbox>
           <description class="text-blurb" id="communityDesc" data-l10n-id="community-2">
-            <label class="text-link" href="http://www.mozilla.org/" data-l10n-name="community-mozillaLink"></label>
-            <label class="text-link" useoriginprincipal="true" href="about:credits" data-l10n-name="community-creditsLink"></label>
+            <label is="text-link" href="http://www.mozilla.org/" data-l10n-name="community-mozillaLink"></label>
+            <label is="text-link" useoriginprincipal="true" href="about:credits" data-l10n-name="community-creditsLink"></label>
           </description>
           <description class="text-blurb" id="contributeDesc" data-l10n-id="helpus">
-            <label class="text-link" href="https://donate.mozilla.org/?utm_source=firefox&#38;utm_medium=referral&#38;utm_campaign=firefox_about&#38;utm_content=firefox_about" data-l10n-name="helpus-donateLink"></label>
-            <label class="text-link" href="http://www.mozilla.org/contribute/" data-l10n-name="helpus-getInvolvedLink"></label>
+            <label is="text-link" href="https://donate.mozilla.org/?utm_source=firefox&#38;utm_medium=referral&#38;utm_campaign=firefox_about&#38;utm_content=firefox_about" data-l10n-name="helpus-donateLink"></label>
+            <label is="text-link" href="http://www.mozilla.org/contribute/" data-l10n-name="helpus-getInvolvedLink"></label>
           </description>
         </vbox>
       </vbox>
     </hbox>
     <vbox id="bottomBox">
       <hbox pack="center">
-        <label class="text-link bottom-link" useoriginprincipal="true" href="about:license" data-l10n-id="bottomLinks-license"></label>
-        <label class="text-link bottom-link" useoriginprincipal="true" href="about:rights" data-l10n-id="bottomLinks-rights"></label>
-        <label class="text-link bottom-link" href="https://www.mozilla.org/privacy/" data-l10n-id="bottomLinks-privacy"></label>
+        <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:license" data-l10n-id="bottomLinks-license"></label>
+        <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:rights" data-l10n-id="bottomLinks-rights"></label>
+        <label is="text-link" class="bottom-link" href="https://www.mozilla.org/privacy/" data-l10n-id="bottomLinks-privacy"></label>
       </hbox>
       <description id="trademark" data-l10n-id="trademarkInfo"></description>
     </vbox>
   </vbox>
 
   <keyset>
     <key keycode="VK_ESCAPE" oncommand="window.close();"/>
   </keyset>
--- a/browser/base/content/browser-media.js
+++ b/browser/base/content/browser-media.js
@@ -33,18 +33,17 @@ var gEMEHandler = {
       return Services.prefs.getBoolPref("media.gmp-widevinecdm.visible");
     }
     return true;
   },
   getEMEDisabledFragment(msgId) {
     let mainMessage = gNavigatorBundle.getString("emeNotifications.drmContentDisabled.message");
     let text = gNavigatorBundle.getString("emeNotifications.drmContentDisabled.learnMoreLabel");
     let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
-    let link = document.createXULElement("label");
-    link.className = "text-link";
+    let link = document.createXULElement("label", {is: "text-link"});
     link.setAttribute("href", baseURL + "drm-content");
     link.textContent = text;
     return BrowserUtils.getLocalizedFragment(document, mainMessage, link);
   },
   getMessageWithBrandName(notificationId) {
     let msgId = "emeNotifications." + notificationId + ".message";
     return gNavigatorBundle.getFormattedString(msgId, [this._brandShortName]);
   },
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -469,18 +469,17 @@ var gPluginHandler = {
 
       buttons.push(submitButton);
     }
 
     notification = notificationBox.appendNotification(messageString, "plugin-crashed",
                                                       iconURL, priority, buttons);
 
     // Add the "learn more" link.
-    let link = notification.ownerDocument.createXULElement("label");
-    link.className = "text-link";
+    let link = notification.ownerDocument.createXULElement("label", {is: "text-link"});
     link.setAttribute("value", gNavigatorBundle.getString("crashedpluginsMessage.learnMore"));
     let crashurl = formatURL("app.support.baseURL", true);
     crashurl += "plugin-crashed-notificationbar";
     link.href = crashurl;
     notification.messageText.appendChild(link);
   },
 };
 
--- a/browser/base/content/browser-siteIdentity.js
+++ b/browser/base/content/browser-siteIdentity.js
@@ -1184,19 +1184,19 @@ var gIdentityHandler = {
     let indicator = document.createXULElement("hbox");
     indicator.setAttribute("class", "identity-popup-permission-item");
     indicator.setAttribute("align", "center");
     indicator.setAttribute("id", "blocked-popup-indicator-item");
 
     let icon = document.createXULElement("image");
     icon.setAttribute("class", "popup-subitem identity-popup-permission-icon");
 
-    let text = document.createXULElement("label");
+    let text = document.createXULElement("label", {is: "text-link"});
     text.setAttribute("flex", "1");
-    text.setAttribute("class", "identity-popup-permission-label text-link");
+    text.setAttribute("class", "identity-popup-permission-label");
 
     let popupCount = gBrowser.selectedBrowser.blockedPopups.length;
     let messageBase = gNavigatorBundle.getString("popupShowBlockedPopupsIndicatorText");
     let message = PluralForm.get(popupCount, messageBase)
                                  .replace("#1", popupCount);
     text.textContent = message;
 
     text.addEventListener("click", () => {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1733,17 +1733,17 @@ var gBrowserInit = {
   /**
    * Use this function as an entry point to schedule tasks that
    * need to run once per window after startup, and can be scheduled
    * by using an idle callback.
    *
    * The functions scheduled here will fire from idle callbacks
    * once every window has finished being restored by session
    * restore, and after the equivalent only-once tasks
-   * have run (from _scheduleStartupIdleTasks in nsBrowserGlue.js).
+   * have run (from _scheduleStartupIdleTasks in BrowserGlue.jsm).
    */
   _schedulePerWindowIdleTasks() {
     // Bail out if the window has been closed in the meantime.
     if (window.closed) {
       return;
     }
 
     function scheduleIdleTask(func, options) {
@@ -2169,17 +2169,17 @@ function BrowserReloadSkipCache() {
   BrowserReloadWithFlags(reloadFlags);
 }
 
 function BrowserHome(aEvent) {
   if (aEvent && "button" in aEvent &&
       aEvent.button == 2) // right-click: do nothing
     return;
 
-  var homePage = HomePage.get(window);
+  var homePage = HomePage.get();
   var where = whereToOpenLink(aEvent, false, true);
   var urls;
   var notifyObservers;
 
   // Home page should open in a new tab when current tab is an app tab
   if (where == "current" &&
       gBrowser &&
       gBrowser.selectedTab.pinned)
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -79,32 +79,32 @@
         <html:ul id="addon-webext-perm-list" class="addon-webext-perm-list"/>
       </popupnotificationcontent>
     </popupnotification>
 
     <popupnotification id="contextual-feature-recommendation-notification" hidden="true">
       <popupnotificationheader id="cfr-notification-header">
         <stack id="cfr-notification-header-stack">
           <description id="cfr-notification-header-label"></description>
-          <label id="cfr-notification-header-link" class="text-link">
+          <label id="cfr-notification-header-link" is="text-link">
             <xul:image id="cfr-notification-header-image"/>
           </label>
         </stack>
       </popupnotificationheader>
       <popupnotificationcontent>
         <description id="cfr-notification-author"></description>
       </popupnotificationcontent>
       <popupnotificationfooter id="cfr-notification-footer" orient="vertical">
         <description id="cfr-notification-footer-text"/>
         <hbox id="cfr-notification-footer-addon-info">
           <hbox id="cfr-notification-footer-filled-stars"/>
           <hbox id="cfr-notification-footer-empty-stars"/>
           <label id="cfr-notification-footer-users"/>
           <spacer id="cfr-notification-footer-spacer" hidden="true"/>
-          <label id="cfr-notification-footer-learn-more-link" class="text-link"/>
+          <label id="cfr-notification-footer-learn-more-link" is="text-link"/>
         </hbox>
       </popupnotificationfooter>
     </popupnotification>
 
     <popupnotification id="storage-access-notification" hidden="true">
       <popupnotificationcontent class="storage-access-notification-content">
         <xul:vbox flex="1">
           <!-- These need to be on the same line to avoid creating
--- a/browser/base/content/test/general/subtst_contextmenu_xul.xul
+++ b/browser/base/content/test/general/subtst_contextmenu_xul.xul
@@ -1,9 +1,9 @@
 <?xml version="1.0"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this file,
    - You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
       xmlns:html="http://www.w3.org/1999/xhtml">
-  <label id="test-xul-text-link-label" class="text-link" value="XUL text-link label" href="https://www.mozilla.com"/>
+  <label id="test-xul-text-link-label" is="text-link" value="XUL text-link label" href="https://www.mozilla.com"/>
 </page>
--- a/browser/base/content/test/performance/browser_startup.js
+++ b/browser/base/content/test/performance/browser_startup.js
@@ -19,32 +19,29 @@
 /* Set this to true only for debugging purpose; it makes the output noisy. */
 const kDumpAllStacks = false;
 
 const startupPhases = {
   // For app-startup, we have a whitelist of acceptable JS files.
   // Anything loaded during app-startup must have a compelling reason
   // to run before we have even selected the user profile.
   // Consider loading your code after first paint instead,
-  // eg. from nsBrowserGlue.js' _onFirstWindowLoaded method).
+  // eg. from BrowserGlue.jsm' _onFirstWindowLoaded method).
   "before profile selection": {whitelist: {
-    components: new Set([
-      "nsBrowserGlue.js",
-      "MainProcessSingleton.js",
-
-      // Bugs to fix: The following components shouldn't be initialized that early.
-      "PushComponents.js", // bug 1369436
-    ]),
     modules: new Set([
+      "resource:///modules/BrowserGlue.jsm",
       "resource://gre/modules/AppConstants.jsm",
       "resource://gre/modules/ActorManagerParent.jsm",
       "resource://gre/modules/CustomElementsListener.jsm",
       "resource://gre/modules/ExtensionUtils.jsm",
+      "resource://gre/modules/MainProcessSingleton.jsm",
       "resource://gre/modules/XPCOMUtils.jsm",
       "resource://gre/modules/Services.jsm",
+      // Bugs to fix: The following components shouldn't be initialized that early.
+      "resource://gre/modules/PushComponents.jsm", // bug 1369436
     ]),
   }},
 
   // For the following phases of startup we have only a black list for now
 
   // We are at this phase after creating the first browser window (ie. after final-ui-startup).
   "before opening first browser window": {blacklist: {
     modules: new Set([
--- a/browser/base/content/test/performance/browser_startup_content.js
+++ b/browser/base/content/test/performance/browser_startup_content.js
@@ -13,24 +13,23 @@
  */
 
 "use strict";
 
 /* Set this to true only for debugging purpose; it makes the output noisy. */
 const kDumpAllStacks = false;
 
 const whitelist = {
-  components: new Set([
-    "ContentProcessSingleton.js",
-  ]),
   modules: new Set([
     "chrome://mochikit/content/ShutdownLeaksCollector.jsm",
     "resource://specialpowers/specialpowers.js",
     "resource://specialpowers/specialpowersAPI.js",
 
+    "resource://gre/modules/ContentProcessSingleton.jsm",
+
     // General utilities
     "resource://gre/modules/AppConstants.jsm",
     "resource://gre/modules/AsyncShutdown.jsm",
     "resource://gre/modules/DeferredTask.jsm",
     "resource://gre/modules/PromiseUtils.jsm",
     "resource://gre/modules/Services.jsm", // bug 1464542
     "resource://gre/modules/Timer.jsm",
     "resource://gre/modules/XPCOMUtils.jsm",
@@ -95,20 +94,18 @@ const whitelist = {
     "data:,new function() {\n      ChromeUtils.import(\"resource://formautofill/FormAutofillContent.jsm\");\n    }",
   ]),
 };
 
 // Items on this list are allowed to be loaded but not
 // required, as opposed to items in the main whitelist,
 // which are all required.
 const intermittently_loaded_whitelist = {
-  components: new Set([
-    "nsAsyncShutdown.js",
-  ]),
   modules: new Set([
+    "resource://gre/modules/nsAsyncShutdown.jsm",
     "resource://gre/modules/sessionstore/Utils.jsm",
   ]),
   frameScripts: new Set([]),
   processScripts: new Set([]),
 };
 
 const blacklist = {
   services: new Set([
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -638,16 +638,20 @@ add_task(async function checkAllTheFiles
     }
 
     return true;
   });
 
   // Wait for all manifest to be parsed
   await throttledMapPromises(manifestURIs, parseManifest);
 
+  for (let jsm of Components.manager.getComponentJSMs()) {
+    gReferencesFromCode.set(jsm, null);
+  }
+
   // manifest.json is a common name, it is used for WebExtension manifests
   // but also for other things.  To tell them apart, we have to actually
   // read the contents.  This will populate gExtensionRoots with all
   // embedded extension APIs, and return any manifest.json files that aren't
   // webextensions.
   let nonWebextManifests = (await Promise.all(jsonManifests.map(parseJsonManifest)))
                                          .filter(uri => !!uri);
   uris.push(...nonWebextManifests);
--- a/browser/base/content/test/tabs/browser_new_web_tab_in_file_process_pref.js
+++ b/browser/base/content/test/tabs/browser_new_web_tab_in_file_process_pref.js
@@ -19,17 +19,16 @@ function CheckBrowserNotInPid(browser, u
 
 // Test for bug 1343184.
 add_task(async function() {
   // Set prefs to ensure file content process, to allow linked web content in
   // file URI process and allow more that one file content process.
   await SpecialPowers.pushPrefEnv(
     {set: [["browser.tabs.remote.separateFileUriProcess", true],
            ["browser.tabs.remote.allowLinkedWebInFileUriProcess", true],
-           ["browser.tabs.remote.useHTTPResponseProcessSelection", false],
            ["dom.ipc.processCount.file", 2]]});
 
   // Open file:// page.
   let dir = getChromeDir(getResolvedURI(gTestPath));
   dir.append(TEST_FILE);
   const uriString = Services.io.newFileURI(dir).spec;
   await BrowserTestUtils.withNewTab(uriString, async function(fileBrowser) {
     // Get the file:// URI pid for comparison later.
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1867,17 +1867,17 @@ file, You can obtain one at http://mozil
           </xul:hbox>
           <xul:hbox anonid="search-suggestions-hint-box" flex="1">
             <xul:description id="search-suggestions-hint">
               <html:span class="prefix">&#x1f4a1; &urlbar.searchSuggestionsNotification.hintPrefix;</html:span>
               <html:span>&urlbar.searchSuggestionsNotification.hint;</html:span>
             </xul:description>
           </xul:hbox>
           <xul:label id="search-suggestions-change-settings"
-                     class="text-link"
+                     is="text-link"
                      role="link"
 #ifdef XP_WIN
                      value="&urlbar.searchSuggestionsNotification.changeSettingsWin;"
                      accesskey="&urlbar.searchSuggestionsNotification.changeSettingsWin.accesskey;"
 #else
                      value="&urlbar.searchSuggestionsNotification.changeSettingsUnix;"
                      accesskey="&urlbar.searchSuggestionsNotification.changeSettingsUnix.accesskey;"
 #endif
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -19,29 +19,20 @@ XPCOMUtils.defineLazyModuleGetters(this,
 
 XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
                                    "@mozilla.org/browser/aboutnewtab-service;1",
                                    "nsIAboutNewTabService");
 
 Object.defineProperty(this, "BROWSER_NEW_TAB_URL", {
   enumerable: true,
   get() {
-    if (PrivateBrowsingUtils.isWindowPrivate(window)) {
-      if (!PrivateBrowsingUtils.permanentPrivateBrowsing &&
-          !aboutNewTabService.overridden) {
-        return "about:privatebrowsing";
-      }
-      // If the extension does not have private browsing permission,
-      // use about:privatebrowsing.
-      if (aboutNewTabService.newTabURL.startsWith("moz-extension")) {
-        let url = new URL(aboutNewTabService.newTabURL);
-        if (!WebExtensionPolicy.getByHostname(url.hostname).privateBrowsingAllowed) {
-          return "about:privatebrowsing";
-        }
-      }
+    if (PrivateBrowsingUtils.isWindowPrivate(window) &&
+        !PrivateBrowsingUtils.permanentPrivateBrowsing &&
+        !aboutNewTabService.overridden) {
+      return "about:privatebrowsing";
     }
     return aboutNewTabService.newTabURL;
   },
 });
 
 var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
 
 var gBidiUI = false;
--- a/browser/components/BrowserComponents.manifest
+++ b/browser/components/BrowserComponents.manifest
@@ -1,43 +1,10 @@
-# nsBrowserContentHandler.js
-component {5d0ce354-df01-421a-83fb-7ead0990c24e} nsBrowserContentHandler.js application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/browser/clh;1 {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-component {47cd0651-b1be-4a0f-b5c4-10e5a573ef71} nsBrowserContentHandler.js application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/browser/final-clh;1 {47cd0651-b1be-4a0f-b5c4-10e5a573ef71} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=text/html {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=application/vnd.mozilla.xul+xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=image/svg+xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=text/rdf {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=text/xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=application/xhtml+xml {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=text/css {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=text/plain {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=image/gif {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=image/jpeg {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=image/jpg {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=image/png {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=image/bmp {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=image/x-icon {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=image/vnd.microsoft.icon {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-contract @mozilla.org/uriloader/content-handler;1?type=application/http-index-format {5d0ce354-df01-421a-83fb-7ead0990c24e} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-category command-line-handler m-browser @mozilla.org/browser/clh;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-category command-line-handler x-default @mozilla.org/browser/final-clh;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-category command-line-validator b-browser @mozilla.org/browser/clh;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
-
 # nsBrowserGlue.js
 
 # This component must restrict its registration for the app-startup category
 # to the specific list of apps that use it so it doesn't get loaded in xpcshell.
 # Thus we restrict it to these apps:
 #
 #   browser:        {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 #   mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110}
 
-component {eab9012e-5f74-4cbc-b2b5-a590235513cc} nsBrowserGlue.js
-contract @mozilla.org/browser/browserglue;1 {eab9012e-5f74-4cbc-b2b5-a590235513cc}
 category app-startup nsBrowserGlue service,@mozilla.org/browser/browserglue;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110}
-component {d8903bf6-68d5-4e97-bcd1-e4d3012f721a} nsBrowserGlue.js
-contract @mozilla.org/content-permission/prompt;1 {d8903bf6-68d5-4e97-bcd1-e4d3012f721a}
-
-# RegisterProtocolHandler support
-component {efbd7b87-9b15-4684-abf0-dc2679daadb1} WebProtocolHandlerRegistrar.js process=main
-contract @mozilla.org/embeddor.implemented/web-protocol-handler-registrar;1 {efbd7b87-9b15-4684-abf0-dc2679daadb1} process=main
rename from browser/components/nsBrowserContentHandler.js
rename to browser/components/BrowserContentHandler.jsm
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/BrowserContentHandler.jsm
@@ -1,12 +1,14 @@
 /* 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/. */
 
+var EXPORTED_SYMBOLS = ["nsBrowserContentHandler", "nsDefaultCommandLineHandler"];
+
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
   HeadlessShell: "resource:///modules/HeadlessShell.jsm",
   HomePage: "resource:///modules/HomePage.jsm",
@@ -173,17 +175,17 @@ function getPostUpdateOverridePage(defau
     return defaultOverridePage;
   }
 
   return update.getProperty("openURL") || defaultOverridePage;
 }
 
 /**
  * Open a browser window. If this is the initial launch, this function will
- * attempt to use the navigator:blank window opened by nsBrowserGlue.js during
+ * attempt to use the navigator:blank window opened by BrowserGlue.jsm during
  * early startup.
  *
  * @param cmdLine
  *        The nsICommandLine object given to nsICommandLineHandler's handle
  *        method.
  *        Used to check if we are processing the command line for the initial launch.
  * @param triggeringPrincipal
  *        The nsIPrincipal to use as triggering principal for the page load(s).
@@ -202,17 +204,17 @@ function getPostUpdateOverridePage(defau
  */
 function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData = null,
                            forcePrivate = false) {
   let chromeURL = AppConstants.BROWSER_CHROME_URL;
 
   let args;
   if (!urlOrUrlList) {
     // Just pass in the defaultArgs directly. We'll use system principal on the other end.
-    args = [gBrowserContentHandler.getDefaultArgs(forcePrivate)];
+    args = [gBrowserContentHandler.defaultArgs];
   } else {
     let pService = Cc["@mozilla.org/toolkit/profile-service;1"].
                   getService(Ci.nsIToolkitProfileService);
     if (cmdLine && cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
         pService.createdAlternateProfile) {
       let url = getNewInstallPage();
       if (Array.isArray(urlOrUrlList)) {
         urlOrUrlList.unshift(url);
@@ -320,28 +322,22 @@ function doSearch(searchTerm, cmdLine) {
   var submission = engine.getSubmission(searchTerm, null, "system");
 
   // XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing
   // preferences, but need nsIBrowserDOMWindow extensions
   openBrowserWindow(cmdLine, gSystemPrincipal, submission.uri.spec, submission.postData);
 }
 
 function nsBrowserContentHandler() {
+  if (!gBrowserContentHandler) {
+    gBrowserContentHandler = this;
+  }
+  return gBrowserContentHandler;
 }
 nsBrowserContentHandler.prototype = {
-  classID: Components.ID("{5d0ce354-df01-421a-83fb-7ead0990c24e}"),
-
-  _xpcom_factory: {
-    createInstance: function bch_factory_ci(outer, iid) {
-      if (outer)
-        throw Cr.NS_ERROR_NO_AGGREGATION;
-      return gBrowserContentHandler.QueryInterface(iid);
-    },
-  },
-
   /* nsISupports */
   QueryInterface: ChromeUtils.generateQI([Ci.nsICommandLineHandler,
                                           Ci.nsIBrowserHandler,
                                           Ci.nsIContentHandler,
                                           Ci.nsICommandLineValidator]),
 
   /* nsICommandLineHandler */
   handle: function bch_handle(cmdLine) {
@@ -517,17 +513,17 @@ nsBrowserContentHandler.prototype = {
     info += "  --window-size width[,height] Width and optionally height of screenshot.\n";
     info += "  --search <term>    Search <term> with your default search engine.\n";
     info += "  --setDefaultBrowser Set this app as the default browser.\n";
     return info;
   },
 
   /* nsIBrowserHandler */
 
-  getDefaultArgs(forcePrivate = false) {
+  get defaultArgs() {
     var prefb = Services.prefs;
 
     if (!gFirstWindow) {
       gFirstWindow = true;
       if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) {
         return "about:privatebrowsing";
       }
     }
@@ -602,17 +598,17 @@ nsBrowserContentHandler.prototype = {
         overridePage = additionalPage;
       }
     }
 
     var startPage = "";
     try {
       var choice = prefb.getIntPref("browser.startup.page");
       if (choice == 1 || choice == 3)
-        startPage = forcePrivate ? HomePage.getPrivate() : HomePage.get();
+        startPage = HomePage.get();
     } catch (e) {
       Cu.reportError(e);
     }
 
     if (startPage == "about:blank")
       startPage = "";
 
     let skipStartPage = ((override == OVERRIDE_NEW_PROFILE) || (override == OVERRIDE_ALTERNATE_PROFILE)) &&
@@ -620,20 +616,16 @@ nsBrowserContentHandler.prototype = {
     // Only show the startPage if we're not restoring an update session and are
     // not set to skip the start page on this profile
     if (overridePage && startPage && !willRestoreSession && !skipStartPage)
       return overridePage + "|" + startPage;
 
     return overridePage || startPage || "about:blank";
   },
 
-  get defaultArgs() {
-    return this.getDefaultArgs(PrivateBrowsingUtils.permanentPrivateBrowsing);
-  },
-
   mFeatures: null,
 
   getFeatures: function bch_features(cmdLine) {
     if (this.mFeatures === null) {
       this.mFeatures = "";
 
       if (cmdLine) {
         try {
@@ -732,18 +724,16 @@ function handURIToExistingBrowser(uri, l
   bwin.openURI(uri, null, location,
                Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL, triggeringPrincipal);
 }
 
 function nsDefaultCommandLineHandler() {
 }
 
 nsDefaultCommandLineHandler.prototype = {
-  classID: Components.ID("{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}"),
-
   /* nsISupports */
   QueryInterface: ChromeUtils.generateQI(["nsICommandLineHandler"]),
 
   _haveProfile: false,
 
   /* nsICommandLineHandler */
   handle: function dch_handle(cmdLine) {
     var urilist = [];
@@ -835,11 +825,8 @@ nsDefaultCommandLineHandler.prototype = 
       let win = Services.wm.getMostRecentWindow("navigator:blank");
       if (win)
         win.close();
     }
   },
 
   helpInfo: "",
 };
-
-var components = [nsBrowserContentHandler, nsDefaultCommandLineHandler];
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
rename from browser/components/nsBrowserGlue.js
rename to browser/components/BrowserGlue.jsm
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/BrowserGlue.jsm
@@ -1,12 +1,14 @@
 /* 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/. */
 
+var EXPORTED_SYMBOLS = ["BrowserGlue", "ContentPermissionPrompt"];
+
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
 ChromeUtils.defineModuleGetter(this, "ActorManagerParent",
                                "resource://gre/modules/ActorManagerParent.jsm");
@@ -360,90 +362,89 @@ let ACTORS = {
   // The window becomes visible after OnStopRequest, so make this happen now.
   win.stop();
 
   let { TelemetryTimestamps } =
     ChromeUtils.import("resource://gre/modules/TelemetryTimestamps.jsm");
   TelemetryTimestamps.add("blankWindowShown");
 })();
 
-XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
-
 XPCOMUtils.defineLazyServiceGetters(this, {
-  WindowsUIUtils: ["@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils"],
   aboutNewTabService: ["@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"],
 });
 XPCOMUtils.defineLazyGetter(this, "WeaveService", () =>
   Cc["@mozilla.org/weave/service;1"].getService().wrappedJSObject
 );
 
 // lazy module getters
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AboutPrivateBrowsingHandler: "resource:///modules/aboutpages/AboutPrivateBrowsingHandler.jsm",
   AddonManager: "resource://gre/modules/AddonManager.jsm",
   AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.jsm",
-  AsyncPrefs: "resource://gre/modules/AsyncPrefs.jsm",
   AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
   AutoCompletePopup: "resource://gre/modules/AutoCompletePopup.jsm",
   Blocklist: "resource://gre/modules/Blocklist.jsm",
   BookmarkHTMLUtils: "resource://gre/modules/BookmarkHTMLUtils.jsm",
   BookmarkJSONUtils: "resource://gre/modules/BookmarkJSONUtils.jsm",
   BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
   BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
-  ContentClick: "resource:///modules/ContentClick.jsm",
   ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
-  CustomizableUI: "resource:///modules/CustomizableUI.jsm",
   DateTimePickerParent: "resource://gre/modules/DateTimePickerParent.jsm",
   Discovery: "resource:///modules/Discovery.jsm",
   ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
   FileSource: "resource://gre/modules/L10nRegistry.jsm",
-  FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
   FxAccounts: "resource://gre/modules/FxAccounts.jsm",
   HomePage: "resource:///modules/HomePage.jsm",
   HybridContentTelemetry: "resource://gre/modules/HybridContentTelemetry.jsm",
   Integration: "resource://gre/modules/Integration.jsm",
   L10nRegistry: "resource://gre/modules/L10nRegistry.jsm",
   LanguagePrompt: "resource://gre/modules/LanguagePrompt.jsm",
   LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
   LiveBookmarkMigrator: "resource:///modules/LiveBookmarkMigrator.jsm",
-  LoginHelper: "resource://gre/modules/LoginHelper.jsm",
-  LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
   NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
   Normandy: "resource://normandy/Normandy.jsm",
   ObjectUtils: "resource://gre/modules/ObjectUtils.jsm",
   OS: "resource://gre/modules/osfile.jsm",
   PageActions: "resource:///modules/PageActions.jsm",
   PageThumbs: "resource://gre/modules/PageThumbs.jsm",
   PdfJs: "resource://pdf.js/PdfJs.jsm",
   PermissionUI: "resource:///modules/PermissionUI.jsm",
-  PictureInPicture: "resource://gre/modules/PictureInPicture.jsm",
   PingCentre: "resource:///modules/PingCentre.jsm",
   PlacesBackups: "resource://gre/modules/PlacesBackups.jsm",
   PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
   PluralForm: "resource://gre/modules/PluralForm.jsm",
   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   ProcessHangMonitor: "resource:///modules/ProcessHangMonitor.jsm",
-  ReaderParent: "resource:///modules/ReaderParent.jsm",
-  RemotePrompt: "resource:///modules/RemotePrompt.jsm",
   RemoteSettings: "resource://services-settings/remote-settings.js",
   SafeBrowsing: "resource://gre/modules/SafeBrowsing.jsm",
   Sanitizer: "resource:///modules/Sanitizer.jsm",
   SaveToPocket: "chrome://pocket/content/SaveToPocket.jsm",
   SearchTelemetry: "resource:///modules/SearchTelemetry.jsm",
   SessionStartup: "resource:///modules/sessionstore/SessionStartup.jsm",
   SessionStore: "resource:///modules/sessionstore/SessionStore.jsm",
   ShellService: "resource:///modules/ShellService.jsm",
   TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
   UIState: "resource://services-sync/UIState.jsm",
   UITour: "resource:///modules/UITour.jsm",
   WebChannel: "resource://gre/modules/WebChannel.jsm",
   WindowsRegistry: "resource://gre/modules/WindowsRegistry.jsm",
 });
 
+// eslint-disable-next-line no-unused-vars
+XPCOMUtils.defineLazyModuleGetters(this, {
+  AsyncPrefs: "resource://gre/modules/AsyncPrefs.jsm",
+  ContentClick: "resource:///modules/ContentClick.jsm",
+  FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
+  LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
+  PictureInPicture: "resource://gre/modules/PictureInPicture.jsm",
+  ReaderParent: "resource:///modules/ReaderParent.jsm",
+  RemotePrompt: "resource:///modules/RemotePrompt.jsm",
+});
+
 /* global ContentPrefServiceParent:false, ContentSearch:false,
           UpdateListener:false, webrtcUI:false */
 
 /**
  * IF YOU ADD OR REMOVE FROM THIS LIST, PLEASE UPDATE THE LIST ABOVE AS WELL.
  * XXX Bug 1325373 is for making eslint detect these automatically.
  */
 
@@ -461,17 +462,16 @@ let initializedModules = {};
     return initializedModules[name];
   });
 });
 
 if (AppConstants.MOZ_CRASHREPORTER) {
   XPCOMUtils.defineLazyModuleGetters(this, {
     PluginCrashReporter: "resource:///modules/ContentCrashHandlers.jsm",
     UnsubmittedCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
-    CrashSubmit: "resource://gre/modules/CrashSubmit.jsm",
   });
 }
 
 XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
   return Services.strings.createBundle("chrome://branding/locale/brand.properties");
 });
 
 XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
@@ -2980,23 +2980,18 @@ BrowserGlue.prototype = {
     if (state.status == UIState.STATUS_LOGIN_FAILED ||
         state.status == UIState.STATUS_NOT_VERIFIED) {
       AppMenuNotifications.showBadgeOnlyNotification("fxa-needs-authentication");
     } else {
       AppMenuNotifications.removeNotification("fxa-needs-authentication");
     }
   },
 
-  // for XPCOM
-  classID:          Components.ID("{eab9012e-5f74-4cbc-b2b5-a590235513cc}"),
-
   QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
                                           Ci.nsISupportsWeakReference]),
-
-  _xpcom_factory: XPCOMUtils.generateSingletonFactory(BrowserGlue),
 };
 
 var ContentBlockingCategoriesPrefs = {
   PREF_CB_CATEGORY: "browser.contentblocking.category",
   // The prefs inside CATEGORY_PREFS set expected value for each CB category.
   // A null value means that pref is default.
   CATEGORY_PREFS: {
     strict: [
@@ -3484,19 +3479,16 @@ var JawsScreenReaderVersionCheck = {
 
     notification =
       win.PopupNotifications.show(browser, "e10s_enabled_with_incompat_jaws",
                                   promptMessage, null, mainAction,
                                   null, options);
   },
 };
 
-var components = [BrowserGlue, ContentPermissionPrompt];
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
-
 // Listen for UITour messages.
 // Do it here instead of the UITour module itself so that the UITour module is lazy loaded
 // when the first message is received.
 Services.mm.addMessageListener("UITour:onPageEvent", function(aMessage) {
   UITour.onPageEvent(aMessage, aMessage.data);
 });
 
 // Listen for HybridContentTelemetry messages.
new file mode 100644
--- /dev/null
+++ b/browser/components/about/components.conf
@@ -0,0 +1,40 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+pages = [
+    'blocked',
+    'certerror',
+    'config',
+    'downloads',
+    'home',
+    'library',
+    'newinstall',
+    'newtab',
+    'pocket-saved',
+    'pocket-signup',
+    'policies',
+    'preferences',
+    'privatebrowsing',
+    'reader',
+    'restartrequired',
+    'rights',
+    'robots',
+    'searchreset',
+    'sessionrestore',
+    'tabcrashed',
+    'welcome',
+    'welcomeback',
+]
+
+Classes = [
+    {
+        'cid': '{7e4bb6ad-2fc4-4dc6-89ef-23e8e5ccf980}',
+        'contract_ids': ['@mozilla.org/network/protocol/about;1?what=%s' % page
+                         for page in pages],
+        'legacy_constructor': 'mozilla::browser::AboutRedirector::Create',
+        'headers': ['/browser/components/about/AboutRedirector.h'],
+    },
+]
--- a/browser/components/about/moz.build
+++ b/browser/components/about/moz.build
@@ -12,16 +12,20 @@ EXPORTS.mozilla.browser += [
 ]
 
 XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
 
 SOURCES += [
     'AboutRedirector.cpp',
 ]
 
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
+
 EXTRA_JS_MODULES.aboutpages = [
     'AboutPrivateBrowsingHandler.jsm',
 ]
 
 FINAL_LIBRARY = 'browsercomps'
 
 LOCAL_INCLUDES += [
     '../build',
new file mode 100644
--- /dev/null
+++ b/browser/components/build/components.conf
@@ -0,0 +1,67 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{6deb193c-f87d-4078-bc78-5e64655b4d62}',
+        'contract_ids': ['@mozilla.org/browser/directory-provider;1'],
+        'type': 'mozilla::browser::DirectoryProvider',
+        'headers': ['mozilla/browser/DirectoryProvider.h'],
+        'categories': {'xpcom-directory-providers': 'browser-directory-provider'},
+    },
+]
+
+TOOLKIT = buildconfig.substs['MOZ_WIDGET_TOOLKIT']
+
+shell_service_contracts = [
+    '@mozilla.org/browser/shell-service;1',
+    '@mozilla.org/toolkit/shell-service;1',
+]
+
+if TOOLKIT == 'gtk3':
+    Classes += [
+        {
+            'cid': '{63c7b9f4-0cc8-43f8-b666-0a661655cb73}',
+            'contract_ids': shell_service_contracts,
+            'type': 'nsGNOMEShellService',
+            'headers': ['/browser/components/shell/nsGNOMEShellService.h'],
+            'init_method': 'Init',
+        },
+    ]
+elif TOOLKIT == 'cocoa':
+    Classes += [
+        {
+            'cid': '{6fc66a78-6cbc-4b3f-b7ba-379289b29276}',
+            'contract_ids': ['@mozilla.org/mac-attribution;1'],
+            'type': 'nsMacAttributionService',
+            'headers': ['nsMacAttribution.h'],
+        },
+    ]
+
+if buildconfig.substs['OS_ARCH'] == 'Darwin':
+    Classes += [
+        {
+            'cid': '{63c7b9f4-0cc8-43f8-b666-0a661655cb73}',
+            'contract_ids': shell_service_contracts,
+            'type': 'nsMacShellService',
+            'headers': ['/browser/components/shell/nsMacShellService.h'],
+        },
+    ]
+elif buildconfig.substs['OS_ARCH'] == 'WINNT':
+    Classes += [
+        {
+            'cid': '{63c7b9f4-0cc8-43f8-b666-0a661655cb73}',
+            'contract_ids': shell_service_contracts,
+            'type': 'nsWindowsShellService',
+            'headers': ['/browser/components/shell/nsWindowsShellService.h'],
+        },
+        {
+            'cid': '{93480624-806e-4756-b7cb-0fb7dd746a8f}',
+            'contract_ids': ['@mozilla.org/profile/migrator/iehistoryenumerator;1'],
+            'type': 'nsIEHistoryEnumerator',
+            'headers': ['/browser/components/migration/nsIEHistoryEnumerator.h'],
+        },
+    ]
--- a/browser/components/build/moz.build
+++ b/browser/components/build/moz.build
@@ -2,22 +2,18 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files("**"):
     BUG_COMPONENT = ("Firefox Build System", "General")
 
-EXPORTS += [
-    'nsBrowserCompsCID.h',
-]
-
-SOURCES += [
-    'nsModule.cpp',
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 Library('browsercomps')
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '../about',
     '../dirprovider',
--- a/browser/components/build/nsBrowserCompsCID.h
+++ b/browser/components/build/nsBrowserCompsCID.h
@@ -35,34 +35,15 @@
 // 136e2c4d-c5a4-477c-b131-d93d7d704f64
 #define NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID      \
   {                                                  \
     0x136e2c4d, 0xc5a4, 0x477c, {                    \
       0xb1, 0x31, 0xd9, 0x3d, 0x7d, 0x70, 0x4f, 0x64 \
     }                                                \
   }
 
-// 7e4bb6ad-2fc4-4dc6-89ef-23e8e5ccf980
-#define NS_BROWSER_ABOUT_REDIRECTOR_CID              \
-  {                                                  \
-    0x7e4bb6ad, 0x2fc4, 0x4dc6, {                    \
-      0x89, 0xef, 0x23, 0xe8, 0xe5, 0xcc, 0xf9, 0x80 \
-    }                                                \
-  }
-
 // {6DEB193C-F87D-4078-BC78-5E64655B4D62}
 #define NS_BROWSERDIRECTORYPROVIDER_CID              \
   {                                                  \
     0x6deb193c, 0xf87d, 0x4078, {                    \
       0xbc, 0x78, 0x5e, 0x64, 0x65, 0x5b, 0x4d, 0x62 \
     }                                                \
   }
-
-#if defined(MOZ_WIDGET_COCOA)
-#  define NS_MACATTRIBUTIONSERVICE_CONTRACTID "@mozilla.org/mac-attribution;1"
-
-#  define NS_MACATTRIBUTIONSERVICE_CID                 \
-    {                                                  \
-      0x6FC66A78, 0x6CBC, 0x4B3F, {                    \
-        0xB7, 0xBA, 0x37, 0x92, 0x89, 0xB2, 0x92, 0x76 \
-      }                                                \
-    }
-#endif
deleted file mode 100644
--- a/browser/components/build/nsModule.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; 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/. */
-
-#include "mozilla/ModuleUtils.h"
-
-#include "nsBrowserCompsCID.h"
-#include "DirectoryProvider.h"
-
-#if defined(XP_WIN)
-#  include "nsWindowsShellService.h"
-#elif defined(XP_MACOSX)
-#  include "nsMacShellService.h"
-#elif defined(MOZ_WIDGET_GTK)
-#  include "nsGNOMEShellService.h"
-#endif
-#include "nsIToolkitShellService.h"
-
-#if defined(MOZ_WIDGET_COCOA)
-#  include "nsMacAttribution.h"
-#endif
-
-#if defined(XP_WIN)
-#  include "nsIEHistoryEnumerator.h"
-#endif
-
-#include "AboutRedirector.h"
-#include "nsIAboutModule.h"
-
-#include "nsNetCID.h"
-
-using namespace mozilla::browser;
-
-/////////////////////////////////////////////////////////////////////////////
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(DirectoryProvider)
-#if defined(XP_WIN)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindowsShellService)
-#elif defined(XP_MACOSX)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacShellService)
-#elif defined(MOZ_WIDGET_GTK)
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init)
-#endif
-
-#if defined(MOZ_WIDGET_COCOA)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacAttributionService)
-#endif
-
-#if defined(XP_WIN)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
-#endif
-
-NS_DEFINE_NAMED_CID(NS_BROWSERDIRECTORYPROVIDER_CID);
-#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
-NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
-#endif
-NS_DEFINE_NAMED_CID(NS_BROWSER_ABOUT_REDIRECTOR_CID);
-#if defined(XP_WIN)
-NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
-#endif
-#if defined(MOZ_WIDGET_COCOA)
-NS_DEFINE_NAMED_CID(NS_MACATTRIBUTIONSERVICE_CID);
-#endif
-
-static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
-    // clang-format off
-    { &kNS_BROWSERDIRECTORYPROVIDER_CID, false, nullptr, DirectoryProviderConstructor },
-#if defined(XP_WIN)
-    { &kNS_SHELLSERVICE_CID, false, nullptr, nsWindowsShellServiceConstructor },
-#elif defined(MOZ_WIDGET_GTK)
-    { &kNS_SHELLSERVICE_CID, false, nullptr, nsGNOMEShellServiceConstructor },
-#elif defined(XP_MACOSX)
-    { &kNS_SHELLSERVICE_CID, false, nullptr, nsMacShellServiceConstructor },
-#endif
-    { &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, nullptr, AboutRedirector::Create },
-#if defined(XP_WIN)
-    { &kNS_WINIEHISTORYENUMERATOR_CID, false, nullptr, nsIEHistoryEnumeratorConstructor },
-#endif
-#if defined(MOZ_WIDGET_COCOA)
-    { &kNS_MACATTRIBUTIONSERVICE_CID, false, nullptr, nsMacAttributionServiceConstructor },
-#endif
-    { nullptr }
-    // clang-format on
-};
-
-static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
-    // clang-format off
-    { NS_BROWSERDIRECTORYPROVIDER_CONTRACTID, &kNS_BROWSERDIRECTORYPROVIDER_CID },
-#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(XP_MACOSX)
-    { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
-    { NS_TOOLKITSHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
-#endif
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "blocked", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "config", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "tabcrashed", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "rights", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "robots", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "searchreset", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "welcomeback", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "home", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "library", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "restartrequired", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "welcome", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "policies", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-saved", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-signup", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newinstall", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-#if defined(XP_WIN)
-    { NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
-#endif
-#if defined(MOZ_WIDGET_COCOA)
-    { NS_MACATTRIBUTIONSERVICE_CONTRACTID, &kNS_MACATTRIBUTIONSERVICE_CID },
-#endif
-    { nullptr }
-    // clang-format on
-};
-
-static const mozilla::Module::CategoryEntry kBrowserCategories[] = {
-    {XPCOM_DIRECTORY_PROVIDER_CATEGORY, "browser-directory-provider",
-     NS_BROWSERDIRECTORYPROVIDER_CONTRACTID},
-    {nullptr}};
-
-static const mozilla::Module kBrowserModule = {mozilla::Module::kVersion,
-                                               kBrowserCIDs, kBrowserContracts,
-                                               kBrowserCategories};
-
-NSMODULE_DEFN(nsBrowserCompsModule) = &kBrowserModule;
new file mode 100644
--- /dev/null
+++ b/browser/components/components.conf
@@ -0,0 +1,55 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{5d0ce354-df01-421a-83fb-7ead0990c24e}',
+        'contract_ids': [
+            '@mozilla.org/browser/clh;1',
+            '@mozilla.org/uriloader/content-handler;1?type=application/http-index-format',
+            '@mozilla.org/uriloader/content-handler;1?type=application/vnd.mozilla.xul+xml',
+            '@mozilla.org/uriloader/content-handler;1?type=application/xhtml+xml',
+            '@mozilla.org/uriloader/content-handler;1?type=image/bmp',
+            '@mozilla.org/uriloader/content-handler;1?type=image/gif',
+            '@mozilla.org/uriloader/content-handler;1?type=image/jpeg',
+            '@mozilla.org/uriloader/content-handler;1?type=image/jpg',
+            '@mozilla.org/uriloader/content-handler;1?type=image/png',
+            '@mozilla.org/uriloader/content-handler;1?type=image/svg+xml',
+            '@mozilla.org/uriloader/content-handler;1?type=image/vnd.microsoft.icon',
+            '@mozilla.org/uriloader/content-handler;1?type=image/x-icon',
+            '@mozilla.org/uriloader/content-handler;1?type=text/css',
+            '@mozilla.org/uriloader/content-handler;1?type=text/html',
+            '@mozilla.org/uriloader/content-handler;1?type=text/plain',
+            '@mozilla.org/uriloader/content-handler;1?type=text/rdf',
+            '@mozilla.org/uriloader/content-handler;1?type=text/xml',
+        ],
+        'jsm': 'resource:///modules/BrowserContentHandler.jsm',
+        'constructor': 'nsBrowserContentHandler',
+        'categories': {
+            'command-line-handler': 'm-browser',
+            'command-line-validator': 'b-browser',
+        },
+    },
+    {
+        'cid': '{47cd0651-b1be-4a0f-b5c4-10e5a573ef71}',
+        'contract_ids': ['@mozilla.org/browser/final-clh;1'],
+        'jsm': 'resource:///modules/BrowserContentHandler.jsm',
+        'constructor': 'nsDefaultCommandLineHandler',
+        'categories': {'command-line-handler': 'x-default'},
+    },
+    {
+        'cid': '{eab9012e-5f74-4cbc-b2b5-a590235513cc}',
+        'contract_ids': ['@mozilla.org/browser/browserglue;1'],
+        'jsm': 'resource:///modules/BrowserGlue.jsm',
+        'constructor': 'BrowserGlue',
+    },
+    {
+        'cid': '{d8903bf6-68d5-4e97-bcd1-e4d3012f721a}',
+        'contract_ids': ['@mozilla.org/content-permission/prompt;1'],
+        'jsm': 'resource:///modules/BrowserGlue.jsm',
+        'constructor': 'ContentPermissionPrompt',
+    },
+]
--- a/browser/components/controlcenter/content/panel.inc.xul
+++ b/browser/components/controlcenter/content/panel.inc.xul
@@ -117,17 +117,17 @@
                   oncommand="ContentBlocking.disableForCurrentPage(); gIdentityHandler.recordClick('unblock_private');" />
           <button id="tracking-action-block"
                   class="panel-button tracking-protection-button"
                   label="&trackingProtection.block6.label;"
                   accesskey="&trackingProtection.block6.accesskey;"
                   oncommand="ContentBlocking.enableForCurrentPage(); gIdentityHandler.recordClick('block');" />
           <label id="identity-popup-content-blocking-report-breakage"
                  onclick="ContentBlocking.showReportBreakageSubview(); gIdentityHandler.recordClick('report_breakage');"
-                 class="text-link subviewkeynav"
+                 is="text-link" class="subviewkeynav"
                  flex="1">&contentBlocking.openBreakageReportView2.label;</label>
         </vbox>
       </hbox>
 
       <!-- Permissions Section -->
       <hbox class="identity-popup-section"
             when-connection="not-secure secure secure-ev secure-cert-user-overridden file extension">
         <vbox id="identity-popup-permissions-content" flex="1" role="group"
@@ -191,46 +191,46 @@
                 class="panel-button"
                 oncommand="gIdentityHandler.removeCertException()"/>
 
         <!-- Connection is Not Secure -->
         <description when-connection="not-secure"
                      and-when-loginforms="secure">&identity.description.insecure;</description>
 
         <!-- Insecure login forms -->
-        <description when-loginforms="insecure">&identity.description.insecureLoginForms; <label id="identity-popup-insecure-login-forms-learn-more" class="text-link plain" value="&identity.learnMore;"/></description>
+        <description when-loginforms="insecure">&identity.description.insecureLoginForms; <label id="identity-popup-insecure-login-forms-learn-more" is="text-link" class="plain" value="&identity.learnMore;"/></description>
 
         <!-- Weak Cipher -->
         <description when-ciphers="weak">&identity.description.weakCipher;</description>
         <description class="identity-popup-warning-yellow"
                      when-ciphers="weak">&identity.description.weakCipher2;</description>
 
         <!-- Active Mixed Content Blocked -->
         <description class="identity-popup-warning-gray"
-                     when-mixedcontent="active-blocked">&identity.description.activeBlocked; <label class="identity-popup-mcb-learn-more text-link plain" value="&identity.learnMore;"/></description>
+                     when-mixedcontent="active-blocked">&identity.description.activeBlocked; <label is="text-link" class="identity-popup-mcb-learn-more plain" value="&identity.learnMore;"/></description>
 
         <!-- Passive Mixed Content Loaded -->
         <description when-mixedcontent="passive-loaded">&identity.description.passiveLoaded;</description>
         <description class="identity-popup-warning-yellow"
-                     when-mixedcontent="passive-loaded">&identity.description.passiveLoaded2; <label class="identity-popup-mcb-learn-more text-link plain" value="&identity.learnMore;"/></description>
+                     when-mixedcontent="passive-loaded">&identity.description.passiveLoaded2; <label is="text-link" class="identity-popup-mcb-learn-more plain" value="&identity.learnMore;"/></description>
 
         <!-- Passive Mixed Content Loaded, Active Mixed Content Blocked -->
         <description when-mixedcontent="passive-loaded active-blocked">&identity.description.passiveLoaded;</description>
         <description when-mixedcontent="passive-loaded active-blocked"
-                     class="identity-popup-warning-yellow">&identity.description.passiveLoaded3; <label class="identity-popup-mcb-learn-more text-link plain" value="&identity.learnMore;"/></description>
+                     class="identity-popup-warning-yellow">&identity.description.passiveLoaded3; <label is="text-link" class="identity-popup-mcb-learn-more plain" value="&identity.learnMore;"/></description>
 
         <!-- Active Mixed Content Blocking Disabled -->
         <description when-mixedcontent="active-loaded"
                      and-when-loginforms="secure">&identity.description.activeLoaded;</description>
         <description when-mixedcontent="active-loaded"
-                     and-when-loginforms="secure">&identity.description.activeLoaded2; <label class="identity-popup-mcb-learn-more text-link plain" value="&identity.learnMore;"/></description>
+                     and-when-loginforms="secure">&identity.description.activeLoaded2; <label is="text-link" class="identity-popup-mcb-learn-more plain" value="&identity.learnMore;"/></description>
         <!-- Show only the first message when there are insecure login forms,
              and make sure the Learn More link is included. -->
         <description when-mixedcontent="active-loaded"
-                     and-when-loginforms="insecure">&identity.description.activeLoaded; <label class="identity-popup-mcb-learn-more text-link plain" value="&identity.learnMore;"/></description>
+                     and-when-loginforms="insecure">&identity.description.activeLoaded; <label is="text-link" class="identity-popup-mcb-learn-more plain" value="&identity.learnMore;"/></description>
 
         <!-- Buttons to enable/disable mixed content blocking. -->
         <button when-mixedcontent="active-blocked"
                 label="&identity.disableMixedContentBlocking.label;"
                 accesskey="&identity.disableMixedContentBlocking.accesskey;"
                 class="panel-button"
                 oncommand="gIdentityHandler.disableMixedContentProtection()"/>
         <button when-mixedcontent="active-loaded"
@@ -315,17 +315,17 @@
 
     <!-- Report Breakage SubView -->
     <panelview id="identity-popup-breakageReportView"
                title="&contentBlocking.breakageReportView.label;"
                descriptionheightworkaround="true">
         <vbox id="identity-popup-breakageReportView-heading">
           <description>&contentBlocking.breakageReportView2.description;</description>
           <label id="identity-popup-breakageReportView-learn-more"
-                 class="text-link">&contentBlocking.breakageReportView.learnMore;</label>
+                 is="text-link">&contentBlocking.breakageReportView.learnMore;</label>
         </vbox>
         <vbox id="identity-popup-breakageReportView-body" class="panel-view-body-unscrollable">
           <vbox class="identity-popup-breakageReportView-collection-section">
             <label>&contentBlocking.breakageReportView.collection.url.label;</label>
             <textbox readonly="true" id="identity-popup-breakageReportView-collection-url"/>
           </vbox>
           <vbox class="identity-popup-breakageReportView-collection-section">
             <label>&contentBlocking.breakageReportView.collection.comments.label;</label>
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -104,17 +104,17 @@
                      secondarybuttonlabel="&updateAvailable.cancelButton.label;"
                      secondarybuttonaccesskey="&updateAvailable.cancelButton.accesskey;"
                      dropmarkerhidden="true"
                      checkboxhidden="true"
                      buttonhighlight="true"
                      hidden="true">
     <popupnotificationcontent id="update-available-notification-content" orient="vertical">
       <description id="update-available-description">&updateAvailable.message;</description>
-      <label id="update-available-whats-new" class="text-link" value="&updateAvailable.whatsnew.label;" />
+      <label id="update-available-whats-new" is="text-link" value="&updateAvailable.whatsnew.label;" />
     </popupnotificationcontent>
   </popupnotification>
 
   <popupnotification id="appMenu-update-manual-notification"
                      popupid="update-manual"
                      label="&updateManual.header.message;"
                      buttonlabel="&updateManual.acceptButton.label;"
                      buttonaccesskey="&updateManual.acceptButton.accesskey;"
@@ -122,17 +122,17 @@
                      secondarybuttonlabel="&updateManual.cancelButton.label;"
                      secondarybuttonaccesskey="&updateManual.cancelButton.accesskey;"
                      dropmarkerhidden="true"
                      checkboxhidden="true"
                      buttonhighlight="true"
                      hidden="true">
     <popupnotificationcontent id="update-manual-notification-content" orient="vertical">
       <description id="update-manual-description">&updateManual.message;</description>
-      <label id="update-manual-whats-new" class="text-link" value="&updateManual.whatsnew.label;" />
+      <label id="update-manual-whats-new" is="text-link" value="&updateManual.whatsnew.label;" />
     </popupnotificationcontent>
   </popupnotification>
 
   <popupnotification id="appMenu-update-restart-notification"
                      popupid="update-restart"
                      label="&updateRestart.header.message2;"
                      buttonlabel="&updateRestart.acceptButton.label;"
                      buttonaccesskey="&updateRestart.acceptButton.accesskey;"
--- a/browser/components/extensions/ExtensionControlledPopup.jsm
+++ b/browser/components/extensions/ExtensionControlledPopup.jsm
@@ -26,18 +26,16 @@ const {XPCOMUtils} = ChromeUtils.import(
 ChromeUtils.defineModuleGetter(this, "AddonManager",
                                "resource://gre/modules/AddonManager.jsm");
 ChromeUtils.defineModuleGetter(this, "BrowserUtils",
                                "resource://gre/modules/BrowserUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "CustomizableUI",
                                "resource:///modules/CustomizableUI.jsm");
 ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
                                "resource://gre/modules/ExtensionSettingsStore.jsm");
-ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
-                               "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 let {
   makeWidgetId,
 } = ExtensionCommon;
 
 XPCOMUtils.defineLazyGetter(this, "strBundle", function() {
   return Services.strings.createBundle("chrome://global/locale/extensions.properties");
 });
@@ -192,30 +190,25 @@ class ExtensionControlledPopup {
     this.removeObserver();
 
     if (!extensionId) {
       let item = ExtensionSettingsStore.getSetting(
         this.settingType, this.settingKey);
       extensionId = item && item.id;
     }
 
-    let win = targetWindow || this.topWindow;
-    let isPrivate = PrivateBrowsingUtils.isWindowPrivate(win);
-    if (isPrivate && extensionId && !WebExtensionPolicy.getByID(extensionId).privateBrowsingAllowed) {
-      return;
-    }
-
     // The item should have an extension and the user shouldn't have confirmed
     // the change here, but just to be sure check that it is still controlled
     // and the user hasn't already confirmed the change.
     // If there is no id, then the extension is no longer in control.
     if (!extensionId || this.userHasConfirmed(extensionId)) {
       return;
     }
 
+    let win = targetWindow || this.topWindow;
     // If the window closes while waiting for focus, this might reject/throw,
     // and we should stop trying to show the popup.
     try {
       await this._ensureWindowReady(win);
     } catch (ex) {
       return;
     }
 
@@ -305,18 +298,18 @@ class ExtensionControlledPopup {
     if (this.getLocalizedDescription) {
       description.appendChild(
         this.getLocalizedDescription(doc, message, addonDetails));
     } else {
       description.appendChild(
         BrowserUtils.getLocalizedFragment(doc, message, addonDetails));
     }
 
-    let link = doc.createXULElement("label");
-    link.setAttribute("class", "learnMore text-link");
+    let link = doc.createXULElement("label", {is: "text-link"});
+    link.setAttribute("class", "learnMore");
     link.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + this.learnMoreLink;
     link.textContent = strBundle.GetStringFromName(this.learnMoreMessageId);
     description.appendChild(link);
   }
 
   _ensureWindowReady(win) {
     return new Promise(async (resolve, reject) => {
       if (win.closed) {
--- a/browser/components/extensions/parent/ext-windows.js
+++ b/browser/components/extensions/parent/ext-windows.js
@@ -186,23 +186,18 @@ this.windows = class extends ExtensionAP
               for (let url of createData.url) {
                 array.appendElement(mkstr(url));
               }
               args.appendElement(array);
             } else {
               args.appendElement(mkstr(createData.url));
             }
           } else {
-            let url;
-            if (createData.incognito) {
-              url = PrivateBrowsingUtils.permanentPrivateBrowsing ?
-                HomePage.getPrivate().split("|", 1)[0] : "about:privatebrowsing";
-            } else {
-              url = HomePage.get().split("|", 1)[0];
-            }
+            let url = createData.incognito && !PrivateBrowsingUtils.permanentPrivateBrowsing ?
+              "about:privatebrowsing" : HomePage.get().split("|", 1)[0];
             args.appendElement(mkstr(url));
 
             if (url.startsWith("about:") &&
                 !context.checkLoadURL(url, {dontReportErrors: true})) {
               // The extension principal cannot directly load about:-URLs,
               // except for about:blank. So use the system principal instead.
               principal = Services.scriptSecurityManager.getSystemPrincipal();
             }
--- a/browser/components/extensions/test/browser/browser_ext_chrome_settings_overrides_home.js
+++ b/browser/components/extensions/test/browser/browser_ext_chrome_settings_overrides_home.js
@@ -417,124 +417,8 @@ add_task(async function test_doorhanger_
   ok(getHomePageURL().endsWith("ext1.html"), "The homepage is still the set");
 
   await BrowserTestUtils.closeWindow(win);
   await ext1.unload();
   await ext2.unload();
 
   ok(!isConfirmed(ext1Id), "The confirmation is cleaned up on uninstall");
 });
-
-add_task(async function test_overriding_home_page_incognito_not_allowed() {
-  await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
-
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      chrome_settings_overrides: {"homepage": "home.html"},
-      name: "extension",
-    },
-    background() {
-      browser.test.sendMessage("url", browser.runtime.getURL("home.html"));
-    },
-    files: {"home.html": "<h1>1</h1>"},
-    useAddonManager: "temporary",
-  });
-
-  await extension.startup();
-  let url = await extension.awaitMessage("url");
-
-  let windowOpenedPromise = BrowserTestUtils.waitForNewWindow({url});
-  let win = OpenBrowserWindow();
-  await windowOpenedPromise;
-  let doc = win.document;
-  let description = doc.getElementById("extension-homepage-notification-description");
-  let panel = doc.getElementById("extension-notification-panel");
-  await promisePopupShown(panel);
-
-  let popupnotification = description.closest("popupnotification");
-  is(description.textContent,
-     "An extension,  extension, changed what you see when you open your homepage and new windows.Learn more",
-     "The extension name is in the popup");
-  is(popupnotification.hidden, false, "The expected popup notification is visible");
-
-  ok(win.gURLBar.value.endsWith("home.html"), "extension is in control");
-  await BrowserTestUtils.closeWindow(win);
-
-  // Verify a private window does not open the extension page.
-  windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
-  win = OpenBrowserWindow({private: true});
-  await windowOpenedPromise;
-  win.BrowserHome();
-  await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
-
-  is(win.gURLBar.value, "", "home page not used in private window");
-
-  await extension.unload();
-  await BrowserTestUtils.closeWindow(win);
-});
-
-add_task(async function test_overriding_home_page_incognito_not_allowed_bypass() {
-  await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
-
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      name: "extension",
-    },
-    background() {
-      browser.test.sendMessage("url", browser.runtime.getURL("home.html"));
-    },
-    files: {"home.html": "<h1>1</h1>"},
-    useAddonManager: "temporary",
-  });
-
-  await extension.startup();
-  let url = await extension.awaitMessage("url");
-
-  // Verify manually setting the pref to the extension page does not work.
-  let changed = promisePrefChangeObserved(HOMEPAGE_URL_PREF);
-  Services.prefs.setStringPref(HOMEPAGE_URL_PREF, url);
-  await changed;
-  let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
-  let win = OpenBrowserWindow({private: true});
-  await windowOpenedPromise;
-  win.BrowserHome();
-  await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
-
-  is(win.gURLBar.value, "", "home page not used in private window");
-  changed = promisePrefChangeObserved(HOMEPAGE_URL_PREF);
-  Services.prefs.clearUserPref(HOMEPAGE_URL_PREF);
-  await changed;
-
-  await extension.unload();
-  await BrowserTestUtils.closeWindow(win);
-});
-
-add_task(async function test_overriding_home_page_incognito_spanning() {
-  await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
-
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      chrome_settings_overrides: {"homepage": "home.html"},
-      name: "private extension",
-      applications: {
-        gecko: {id: "@spanning-home"},
-      },
-    },
-    files: {"home.html": "<h1>1</h1>"},
-    useAddonManager: "permanent",
-    incognitoOverride: "spanning",
-  });
-
-  await extension.startup();
-
-  let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
-  let win = OpenBrowserWindow({private: true});
-  await windowOpenedPromise;
-  let doc = win.document;
-  let panel = doc.getElementById("extension-notification-panel");
-  win.BrowserHome();
-  await promisePopupShown(panel);
-
-  ok(win.gURLBar.value.endsWith("home.html"), "extension is in control in private window");
-
-  await extension.unload();
-  await BrowserTestUtils.closeWindow(win);
-});
--- a/browser/components/extensions/test/browser/browser_ext_url_overrides_newtab.js
+++ b/browser/components/extensions/test/browser/browser_ext_url_overrides_newtab.js
@@ -1,18 +1,15 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 
 "use strict";
 
 ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
                                "resource://gre/modules/ExtensionSettingsStore.jsm");
-XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
-                                   "@mozilla.org/browser/aboutnewtab-service;1",
-                                   "nsIAboutNewTabService");
 
 const NEWTAB_URI_1 = "webext-newtab-1.html";
 
 function getNotificationSetting(extensionId) {
   return ExtensionSettingsStore.getSetting("newTabNotification", extensionId);
 }
 
 function getNewTabDoorhanger() {
@@ -520,194 +517,8 @@ add_task(async function dontTemporarilyS
   is(gURLBar.value, "", "URL bar value should be empty.");
   ContentTask.spawn(tab.linkedBrowser, null, function() {
     is(content.document.body.textContent, "New tab!", "New tab page is loaded.");
   });
 
   BrowserTestUtils.removeTab(tab);
   await extension.unload();
 });
-
-add_task(async function test_overriding_newtab_incognito_not_allowed() {
-  await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
-
-  let panel = getNewTabDoorhanger().closest("panel");
-
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      chrome_url_overrides: {"newtab": "newtab.html"},
-      name: "extension",
-      applications: {
-        gecko: {id: "@not-allowed-newtab"},
-      },
-    },
-    files: {
-      "newtab.html": `
-        <!DOCTYPE html>
-        <head>
-          <meta charset="utf-8"/></head>
-        <html>
-          <body>
-            <script src="newtab.js"></script>
-          </body>
-        </html>
-      `,
-
-      "newtab.js": function() {
-        window.onload = () => {
-          browser.test.sendMessage("from-newtab-page", window.location.href);
-        };
-      },
-    },
-    useAddonManager: "permanent",
-  });
-
-  await extension.startup();
-
-  let popupShown = promisePopupShown(panel);
-  BrowserOpenTab();
-  await popupShown;
-
-  let url = await extension.awaitMessage("from-newtab-page");
-  ok(url.endsWith("newtab.html"),
-     "Newtab url is overridden by the extension.");
-
-  // This will show a confirmation doorhanger, make sure we don't leave it open.
-  let popupHidden = promisePopupHidden(panel);
-  panel.hidePopup();
-  await popupHidden;
-
-  BrowserTestUtils.removeTab(gBrowser.selectedTab);
-
-  // Verify a private window does not open the extension page.  We would
-  // get an extra notification that we don't listen for if it gets loaded.
-  let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
-  let win = OpenBrowserWindow({private: true});
-  await windowOpenedPromise;
-
-  let newTabOpened = waitForNewTab();
-  win.BrowserOpenTab();
-  await newTabOpened;
-
-  is(win.gURLBar.value, "", "newtab not used in private window");
-
-  // Verify setting the pref directly doesn't bypass permissions.
-  let origUrl = aboutNewTabService.newTabURL;
-  aboutNewTabService.newTabURL = url;
-  newTabOpened = waitForNewTab();
-  win.BrowserOpenTab();
-  await newTabOpened;
-
-  is(win.gURLBar.value, "", "directly set newtab not used in private window");
-
-  aboutNewTabService.newTabURL = origUrl;
-
-  await extension.unload();
-  await BrowserTestUtils.closeWindow(win);
-});
-
-add_task(async function test_overriding_newtab_incognito_not_allowed_bypass() {
-  await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
-
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      name: "extension",
-      applications: {
-        gecko: {id: "@not-allowed-newtab"},
-      },
-    },
-    background() {
-      browser.test.sendMessage("url", browser.runtime.getURL("newtab.html"));
-    },
-    files: {
-      "newtab.html": `
-        <!DOCTYPE html>
-        <head>
-          <meta charset="utf-8"/></head>
-        <html>
-          <body>
-          </body>
-        </html>
-      `,
-    },
-    useAddonManager: "permanent",
-  });
-
-  await extension.startup();
-  let url = await extension.awaitMessage("url");
-
-  // Verify setting the pref directly doesn't bypass permissions.
-  let origUrl = aboutNewTabService.newTabURL;
-  aboutNewTabService.newTabURL = url;
-
-  // Verify a private window does not open the extension page.  We would
-  // get an extra notification that we don't listen for if it gets loaded.
-  let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
-  let win = OpenBrowserWindow({private: true});
-  await windowOpenedPromise;
-
-  let newTabOpened = waitForNewTab();
-  win.BrowserOpenTab();
-  await newTabOpened;
-
-  is(win.gURLBar.value, "", "directly set newtab not used in private window");
-
-  aboutNewTabService.newTabURL = origUrl;
-
-  await extension.unload();
-  await BrowserTestUtils.closeWindow(win);
-});
-
-add_task(async function test_overriding_newtab_incognito_spanning() {
-  await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
-
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      chrome_url_overrides: {"newtab": "newtab.html"},
-      name: "extension",
-      applications: {
-        gecko: {id: "@spanning-newtab"},
-      },
-    },
-    files: {
-      "newtab.html": `
-        <!DOCTYPE html>
-        <head>
-          <meta charset="utf-8"/></head>
-        <html>
-          <body>
-            <script src="newtab.js"></script>
-          </body>
-        </html>
-      `,
-
-      "newtab.js": function() {
-        window.onload = () => {
-          browser.test.sendMessage("from-newtab-page", window.location.href);
-        };
-      },
-    },
-    useAddonManager: "permanent",
-    incognitoOverride: "spanning",
-  });
-
-  await extension.startup();
-
-  let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
-  let win = OpenBrowserWindow({private: true});
-  await windowOpenedPromise;
-  let panel = win.document.getElementById("extension-new-tab-notification").closest("panel");
-  let popupShown = promisePopupShown(panel);
-  win.BrowserOpenTab();
-  await popupShown;
-
-  let url = await extension.awaitMessage("from-newtab-page");
-  ok(url.endsWith("newtab.html"),
-     "Newtab url is overridden by the extension.");
-
-  // This will show a confirmation doorhanger, make sure we don't leave it open.
-  let popupHidden = promisePopupHidden(panel);
-  panel.hidePopup();
-  await popupHidden;
-
-  await extension.unload();
-  await BrowserTestUtils.closeWindow(win);
-});
rename from browser/components/migration/360seProfileMigrator.js
rename to browser/components/migration/360seProfileMigrator.jsm
--- a/browser/components/migration/360seProfileMigrator.js
+++ b/browser/components/migration/360seProfileMigrator.jsm
@@ -316,9 +316,9 @@ Qihoo360seProfileMigrator.prototype.getL
     return new Date(Math.max.apply(Math, dates));
   });
 };
 
 Qihoo360seProfileMigrator.prototype.classDescription = "360 Secure Browser Profile Migrator";
 Qihoo360seProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=360se";
 Qihoo360seProfileMigrator.prototype.classID = Components.ID("{d0037b95-296a-4a4e-94b2-c3d075d20ab1}");
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Qihoo360seProfileMigrator]);
+var EXPORTED_SYMBOLS = ["Qihoo360seProfileMigrator"];
deleted file mode 100644
--- a/browser/components/migration/BrowserProfileMigrators.manifest
+++ /dev/null
@@ -1,38 +0,0 @@
-component {6F8BB968-C14F-4D6F-9733-6C6737B35DCE} ProfileMigrator.js
-contract @mozilla.org/toolkit/profile-migrator;1 {6F8BB968-C14F-4D6F-9733-6C6737B35DCE}
-
-#if defined(XP_WIN) || defined(XP_MACOSX)
-component {4bf85aa5-4e21-46ca-825f-f9c51a5e8c76} ChromeProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=canary {4bf85aa5-4e21-46ca-825f-f9c51a5e8c76}
-#else
-component {47f75963-840b-4950-a1f0-d9c1864f8b8e} ChromeProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=chrome-beta {47f75963-840b-4950-a1f0-d9c1864f8b8e}
-component {7370a02a-4886-42c3-a4ec-d48c726ec30a} ChromeProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=chrome-dev {7370a02a-4886-42c3-a4ec-d48c726ec30a}
-#endif
-component {4cec1de4-1671-4fc3-a53e-6c539dc77a26} ChromeProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=chrome {4cec1de4-1671-4fc3-a53e-6c539dc77a26}
-component {8cece922-9720-42de-b7db-7cef88cb07ca} ChromeProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=chromium {8cece922-9720-42de-b7db-7cef88cb07ca}
-
-component {91185366-ba97-4438-acba-48deaca63386} FirefoxProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=firefox {91185366-ba97-4438-acba-48deaca63386}
-
-#ifdef HAS_IE_MIGRATOR
-component {3d2532e3-4932-4774-b7ba-968f5899d3a4} IEProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=ie {3d2532e3-4932-4774-b7ba-968f5899d3a4}
-#endif
-
-#ifdef HAS_EDGE_MIGRATOR
-component {62e8834b-2d17-49f5-96ff-56344903a2ae} EdgeProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=edge {62e8834b-2d17-49f5-96ff-56344903a2ae}
-#endif
-
-#ifdef HAS_SAFARI_MIGRATOR
-component {4b609ecf-60b2-4655-9df4-dc149e474da1} SafariProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=safari {4b609ecf-60b2-4655-9df4-dc149e474da1}
-#endif
-#ifdef HAS_360SE_MIGRATOR
-component {d0037b95-296a-4a4e-94b2-c3d075d20ab1} 360seProfileMigrator.js
-contract @mozilla.org/profile/migrator;1?app=browser&type=360se {d0037b95-296a-4a4e-94b2-c3d075d20ab1}
-#endif
rename from browser/components/migration/ChromeProfileMigrator.js
rename to browser/components/migration/ChromeProfileMigrator.jsm
--- a/browser/components/migration/ChromeProfileMigrator.js
+++ b/browser/components/migration/ChromeProfileMigrator.jsm
@@ -11,17 +11,16 @@ const AUTH_TYPE = {
   SCHEME_BASIC: 1,
   SCHEME_DIGEST: 2,
 };
 
 const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 const {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
 const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {ChromeMigrationUtils} = ChromeUtils.import("resource:///modules/ChromeMigrationUtils.jsm");
 const {MigrationUtils, MigratorPrototype} = ChromeUtils.import("resource:///modules/MigrationUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "PlacesUtils",
                                "resource://gre/modules/PlacesUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "OSCrypto",
                                "resource://gre/modules/OSCrypto.jsm");
 
@@ -427,32 +426,32 @@ function ChromiumProfileMigrator() {
   this._chromeUserDataPathSuffix = "Chromium";
 }
 
 ChromiumProfileMigrator.prototype = Object.create(ChromeProfileMigrator.prototype);
 ChromiumProfileMigrator.prototype.classDescription = "Chromium Profile Migrator";
 ChromiumProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=chromium";
 ChromiumProfileMigrator.prototype.classID = Components.ID("{8cece922-9720-42de-b7db-7cef88cb07ca}");
 
-var componentsArray = [ChromeProfileMigrator, ChromiumProfileMigrator];
+var EXPORTED_SYMBOLS = ["ChromeProfileMigrator", "ChromiumProfileMigrator"];
 
 /**
  * Chrome Canary
  * Not available on Linux
  **/
 function CanaryProfileMigrator() {
   this._chromeUserDataPathSuffix = "Canary";
 }
 CanaryProfileMigrator.prototype = Object.create(ChromeProfileMigrator.prototype);
 CanaryProfileMigrator.prototype.classDescription = "Chrome Canary Profile Migrator";
 CanaryProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=canary";
 CanaryProfileMigrator.prototype.classID = Components.ID("{4bf85aa5-4e21-46ca-825f-f9c51a5e8c76}");
 
 if (AppConstants.platform == "win" || AppConstants.platform == "macosx") {
-  componentsArray.push(CanaryProfileMigrator);
+  EXPORTED_SYMBOLS.push("CanaryProfileMigrator");
 }
 
 /**
  * Chrome Dev / Unstable and Beta. Only separate from `regular` chrome on Linux
  */
 if (AppConstants.platform != "win" && AppConstants.platform != "macosx") {
   function ChromeDevMigrator() {
     this._chromeUserDataPathSuffix = "Chrome Dev";
@@ -465,12 +464,10 @@ if (AppConstants.platform != "win" && Ap
   function ChromeBetaMigrator() {
     this._chromeUserDataPathSuffix = "Chrome Beta";
   }
   ChromeBetaMigrator.prototype = Object.create(ChromeProfileMigrator.prototype);
   ChromeBetaMigrator.prototype.classDescription = "Chrome Beta Profile Migrator";
   ChromeBetaMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=chrome-beta";
   ChromeBetaMigrator.prototype.classID = Components.ID("{47f75963-840b-4950-a1f0-d9c1864f8b8e}");
 
-  componentsArray.push(ChromeDevMigrator, ChromeBetaMigrator);
+  EXPORTED_SYMBOLS.push("ChromeDevMigrator", "ChromeBetaMigrator");
 }
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(componentsArray);
rename from browser/components/migration/EdgeProfileMigrator.js
rename to browser/components/migration/EdgeProfileMigrator.jsm
--- a/browser/components/migration/EdgeProfileMigrator.js
+++ b/browser/components/migration/EdgeProfileMigrator.jsm
@@ -491,9 +491,9 @@ EdgeProfileMigrator.prototype.__defineGe
   return true;
 });
 
 
 EdgeProfileMigrator.prototype.classDescription = "Edge Profile Migrator";
 EdgeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=edge";
 EdgeProfileMigrator.prototype.classID = Components.ID("{62e8834b-2d17-49f5-96ff-56344903a2ae}");
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EdgeProfileMigrator]);
+var EXPORTED_SYMBOLS = ["EdgeProfileMigrator"];
rename from browser/components/migration/FirefoxProfileMigrator.js
rename to browser/components/migration/FirefoxProfileMigrator.jsm
--- a/browser/components/migration/FirefoxProfileMigrator.js
+++ b/browser/components/migration/FirefoxProfileMigrator.jsm
@@ -8,17 +8,16 @@
 
 /*
  * Migrates from a Firefox profile in a lossy manner in order to clean up a
  * user's profile.  Data is only migrated where the benefits outweigh the
  * potential problems caused by importing undesired/invalid configurations
  * from the source profile.
  */
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {MigrationUtils, MigratorPrototype} = ChromeUtils.import("resource:///modules/MigrationUtils.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "PlacesBackups",
                                "resource://gre/modules/PlacesBackups.jsm");
 ChromeUtils.defineModuleGetter(this, "SessionMigration",
                                "resource:///modules/sessionstore/SessionMigration.jsm");
 ChromeUtils.defineModuleGetter(this, "OS",
@@ -271,9 +270,9 @@ Object.defineProperty(FirefoxProfileMigr
   get: () => true,
 });
 
 
 FirefoxProfileMigrator.prototype.classDescription = "Firefox Profile Migrator";
 FirefoxProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=firefox";
 FirefoxProfileMigrator.prototype.classID = Components.ID("{91185366-ba97-4438-acba-48deaca63386}");
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FirefoxProfileMigrator]);
+var EXPORTED_SYMBOLS = ["FirefoxProfileMigrator"];
rename from browser/components/migration/IEProfileMigrator.js
rename to browser/components/migration/IEProfileMigrator.jsm
--- a/browser/components/migration/IEProfileMigrator.js
+++ b/browser/components/migration/IEProfileMigrator.jsm
@@ -351,9 +351,9 @@ IEProfileMigrator.prototype.getLastUsedD
     return new Date(Math.max.apply(Math, dates));
   });
 };
 
 IEProfileMigrator.prototype.classDescription = "IE Profile Migrator";
 IEProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=ie";
 IEProfileMigrator.prototype.classID = Components.ID("{3d2532e3-4932-4774-b7ba-968f5899d3a4}");
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IEProfileMigrator]);
+var EXPORTED_SYMBOLS = ["IEProfileMigrator"];
rename from browser/components/migration/ProfileMigrator.js
rename to browser/components/migration/ProfileMigrator.jsm
--- a/browser/components/migration/ProfileMigrator.js
+++ b/browser/components/migration/ProfileMigrator.jsm
@@ -1,21 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {MigrationUtils} = ChromeUtils.import("resource:///modules/MigrationUtils.jsm");
 
 function ProfileMigrator() {
 }
 
 ProfileMigrator.prototype = {
   migrate: MigrationUtils.startupMigration.bind(MigrationUtils),
   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]);
+var EXPORTED_SYMBOLS = ["ProfileMigrator"];
rename from browser/components/migration/SafariProfileMigrator.js
rename to browser/components/migration/SafariProfileMigrator.jsm
--- a/browser/components/migration/SafariProfileMigrator.js
+++ b/browser/components/migration/SafariProfileMigrator.jsm
@@ -377,9 +377,9 @@ Object.defineProperty(SafariProfileMigra
     return this._mainPreferencesPropertyList;
   },
 });
 
 SafariProfileMigrator.prototype.classDescription = "Safari Profile Migrator";
 SafariProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=safari";
 SafariProfileMigrator.prototype.classID = Components.ID("{4b609ecf-60b2-4655-9df4-dc149e474da1}");
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SafariProfileMigrator]);
+var EXPORTED_SYMBOLS = ["SafariProfileMigrator"];
new file mode 100644
--- /dev/null
+++ b/browser/components/migration/components.conf
@@ -0,0 +1,92 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XP_WIN = buildconfig.substs['OS_ARCH'] == 'WINNT'
+XP_MACOSX = buildconfig.substs['MOZ_WIDGET_TOOLKIT'] == 'cocoa'
+
+Classes = [
+    {
+        'cid': '{6F8BB968-C14F-4D6F-9733-6C6737B35DCE}',
+        'contract_ids': ['@mozilla.org/toolkit/profile-migrator;1'],
+        'jsm': 'resource:///modules/ProfileMigrator.jsm',
+        'constructor': 'ProfileMigrator',
+    },
+    {
+        'cid': '{4cec1de4-1671-4fc3-a53e-6c539dc77a26}',
+        'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=chrome'],
+        'jsm': 'resource:///modules/ChromeProfileMigrator.jsm',
+        'constructor': 'ChromeProfileMigrator',
+    },
+    {
+        'cid': '{8cece922-9720-42de-b7db-7cef88cb07ca}',
+        'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=chromium'],
+        'jsm': 'resource:///modules/ChromeProfileMigrator.jsm',
+        'constructor': 'ChromiumProfileMigrator',
+    },
+    {
+        'cid': '{91185366-ba97-4438-acba-48deaca63386}',
+        'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=firefox'],
+        'jsm': 'resource:///modules/FirefoxProfileMigrator.jsm',
+        'constructor': 'FirefoxProfileMigrator',
+    },
+]
+
+if XP_WIN or XP_MACOSX:
+    Classes += [
+        {
+            'cid': '{4bf85aa5-4e21-46ca-825f-f9c51a5e8c76}',
+            'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=canary'],
+            'jsm': 'resource:///modules/ChromeProfileMigrator.jsm',
+            'constructor': 'CanaryProfileMigrator',
+        },
+    ]
+else:
+    Classes += [
+        {
+            'cid': '{47f75963-840b-4950-a1f0-d9c1864f8b8e}',
+            'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=chrome-beta'],
+            'jsm': 'resource:///modules/ChromeProfileMigrator.jsm',
+            'constructor': '  ChromeBetaMigrator',
+        },
+        {
+            'cid': '{7370a02a-4886-42c3-a4ec-d48c726ec30a}',
+            'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=chrome-dev'],
+            'jsm': 'resource:///modules/ChromeProfileMigrator.jsm',
+            'constructor': '  ChromeDevMigrator',
+        },
+    ]
+
+if XP_WIN:
+    Classes += [
+        {
+            'cid': '{3d2532e3-4932-4774-b7ba-968f5899d3a4}',
+            'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=ie'],
+            'jsm': 'resource:///modules/IEProfileMigrator.jsm',
+            'constructor': 'IEProfileMigrator',
+        },
+        {
+            'cid': '{62e8834b-2d17-49f5-96ff-56344903a2ae}',
+            'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=edge'],
+            'jsm': 'resource:///modules/EdgeProfileMigrator.jsm',
+            'constructor': 'EdgeProfileMigrator',
+        },
+        {
+            'cid': '{d0037b95-296a-4a4e-94b2-c3d075d20ab1}',
+            'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=360se'],
+            'jsm': 'resource:///modules/360seProfileMigrator.jsm',
+            'constructor': 'Qihoo360seProfileMigrator',
+        },
+    ]
+
+if XP_MACOSX:
+    Classes += [
+        {
+            'cid': '{4b609ecf-60b2-4655-9df4-dc149e474da1}',
+            'contract_ids': ['@mozilla.org/profile/migrator;1?app=browser&type=safari'],
+            'jsm': 'resource:///modules/SafariProfileMigrator.jsm',
+            'constructor': 'SafariProfileMigrator',
+        },
+    ]
--- a/browser/components/migration/moz.build
+++ b/browser/components/migration/moz.build
@@ -11,50 +11,41 @@ MARIONETTE_UNIT_MANIFESTS += ['tests/mar
 JAR_MANIFESTS += ['jar.mn']
 
 XPIDL_SOURCES += [
     'nsIBrowserProfileMigrator.idl',
 ]
 
 XPIDL_MODULE = 'migration'
 
-EXTRA_COMPONENTS += [
-    'ChromeProfileMigrator.js',
-    'FirefoxProfileMigrator.js',
-    'ProfileMigrator.js',
-]
-
-EXTRA_PP_COMPONENTS += [
-    'BrowserProfileMigrators.manifest',
-]
-
 EXTRA_JS_MODULES += [
     'ChromeMigrationUtils.jsm',
+    'ChromeProfileMigrator.jsm',
+    'FirefoxProfileMigrator.jsm',
     'MigrationUtils.jsm',
+    'ProfileMigrator.jsm',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     SOURCES += [
         'nsIEHistoryEnumerator.cpp',
     ]
-    EXTRA_COMPONENTS += [
-        '360seProfileMigrator.js',
-        'EdgeProfileMigrator.js',
-        'IEProfileMigrator.js',
-    ]
     EXTRA_JS_MODULES += [
+        '360seProfileMigrator.jsm',
+        'EdgeProfileMigrator.jsm',
         'ESEDBReader.jsm',
+        'IEProfileMigrator.jsm',
         'MSMigrationUtils.jsm',
     ]
-    DEFINES['HAS_360SE_MIGRATOR'] = True
-    DEFINES['HAS_IE_MIGRATOR'] = True
-    DEFINES['HAS_EDGE_MIGRATOR'] = True
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
-    EXTRA_COMPONENTS += [
-        'SafariProfileMigrator.js',
+    EXTRA_JS_MODULES += [
+        'SafariProfileMigrator.jsm',
     ]
-    DEFINES['HAS_SAFARI_MIGRATOR'] = True
+
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
 
 FINAL_LIBRARY = 'browsercomps'
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'Migration')
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -69,25 +69,29 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
     DIRS += ['touchbar']
 
 XPIDL_SOURCES += [
     'nsIBrowserHandler.idl',
 ]
 
 XPIDL_MODULE = 'browsercompsbase'
 
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
+
 EXTRA_COMPONENTS += [
     'BrowserComponents.manifest',
-    'nsBrowserContentHandler.js',
-    'nsBrowserGlue.js',
     'tests/startupRecorder.js',
     'tests/testComponents.manifest',
 ]
 
 EXTRA_JS_MODULES += [
+    'BrowserContentHandler.jsm',
+    'BrowserGlue.jsm',
     'distribution.js',
 ]
 
 BROWSER_CHROME_MANIFESTS += [
     'safebrowsing/content/test/browser.ini',
     'tests/browser/browser.ini'
 ]
 
rename from browser/components/newtab/aboutNewTabService.js
rename to browser/components/newtab/AboutNewTabService.jsm
--- a/browser/components/newtab/aboutNewTabService.js
+++ b/browser/components/newtab/AboutNewTabService.jsm
@@ -356,9 +356,9 @@ AboutNewTabService.prototype = {
     Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
     if (!IS_RELEASE_OR_BETA) {
       Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
     }
     this.initialized = false;
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AboutNewTabService]);
+var EXPORTED_SYMBOLS = ["AboutNewTabService"];
deleted file mode 100644
--- a/browser/components/newtab/NewTabComponents.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {dfcd2adc-7867-4d3a-ba70-17501f208142} aboutNewTabService.js
-contract @mozilla.org/browser/aboutnewtab-service;1 {dfcd2adc-7867-4d3a-ba70-17501f208142}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/components.conf
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{dfcd2adc-7867-4d3a-ba70-17501f208142}',
+        'contract_ids': ['@mozilla.org/browser/aboutnewtab-service;1'],
+        'jsm': 'resource:///modules/AboutNewTabService.jsm',
+        'constructor': 'AboutNewTabService',
+    },
+]
--- a/browser/components/newtab/lib/AboutPreferences.jsm
+++ b/browser/components/newtab/lib/AboutPreferences.jsm
@@ -131,18 +131,18 @@ this.AboutPreferences = class AboutPrefe
   }
 
   /**
    * Render preferences to an about:preferences content window with the provided
    * strings and preferences structure.
    */
   renderPreferences({document, Preferences, gHomePane}, strings, prefStructure, discoveryStreamConfig) {
     // Helper to create a new element and append it
-    const createAppend = (tag, parent) => parent.appendChild(
-      document.createXULElement(tag));
+    const createAppend = (tag, parent, options) => parent.appendChild(
+      document.createXULElement(tag, options));
 
     // Helper to get strings and format with values if necessary
     const formatString = id => {
       if (typeof id !== "object") {
         return strings[id] || id;
       }
       let string = strings[id.id] || JSON.stringify(id);
       if (id.values) {
@@ -220,19 +220,18 @@ this.AboutPreferences = class AboutPrefe
 
       // Specially add a link for stories
       if (id === "topstories") {
         const sponsoredHbox = createAppend("hbox", sectionVbox);
         sponsoredHbox.setAttribute("align", "center");
         sponsoredHbox.appendChild(checkbox);
         checkbox.classList.add("tail-with-learn-more");
 
-        const link = createAppend("label", sponsoredHbox);
+        const link = createAppend("label", sponsoredHbox, {is: "text-link"});
         link.classList.add("learn-sponsored");
-        link.classList.add("text-link");
         link.setAttribute("href", sectionData.learnMore.link.href);
         link.textContent = formatString(sectionData.learnMore.link.id);
       }
 
       // Add more details for the section (e.g., description, more prefs)
       const detailVbox = createAppend("vbox", sectionVbox);
       detailVbox.classList.add("indent");
       if (descString) {
--- a/browser/components/newtab/moz.build
+++ b/browser/components/newtab/moz.build
@@ -14,14 +14,17 @@ XPCSHELL_TESTS_MANIFESTS += [
 ]
 
 XPIDL_SOURCES += [
     'nsIAboutNewTabService.idl',
 ]
 
 XPIDL_MODULE = 'browser-newtab'
 
-EXTRA_COMPONENTS += [
-    'aboutNewTabService.js',
-    'NewTabComponents.manifest',
+EXTRA_JS_MODULES += [
+    'AboutNewTabService.jsm',
+]
+
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 JAR_MANIFESTS += ['jar.mn']
rename from browser/components/payments/paymentUIService.js
rename to browser/components/payments/PaymentUIService.jsm
--- a/browser/components/payments/paymentUIService.js
+++ b/browser/components/payments/PaymentUIService.jsm
@@ -296,9 +296,9 @@ PaymentUIService.prototype = {
       case "SwapDocShells": {
         this._moveDialogToNewBrowser(event.target, event.detail);
         break;
       }
     }
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentUIService]);
+var EXPORTED_SYMBOLS = ["PaymentUIService"];
new file mode 100644
--- /dev/null
+++ b/browser/components/payments/components.conf
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{01f8bd55-9017-438b-85ec-7c15d2b35cdc}',
+        'contract_ids': ['@mozilla.org/dom/payments/payment-ui-service;1'],
+        'jsm': 'resource:///modules/PaymentUIService.jsm',
+        'constructor': 'PaymentUIService',
+    },
+]
--- a/browser/components/payments/moz.build
+++ b/browser/components/payments/moz.build
@@ -4,19 +4,22 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'WebPayments UI')
 
-EXTRA_COMPONENTS += [
-    'payments.manifest',
-    'paymentUIService.js',
+EXTRA_JS_MODULES += [
+    'PaymentUIService.jsm',
+]
+
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 JAR_MANIFESTS += ['jar.mn']
 
 MOCHITEST_MANIFESTS += [
     'test/mochitest/formautofill/mochitest.ini',
     'test/mochitest/mochitest.ini',
 ]
deleted file mode 100644
--- a/browser/components/payments/payments.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {01f8bd55-9017-438b-85ec-7c15d2b35cdc} paymentUIService.js
-contract @mozilla.org/dom/payments/payment-ui-service;1 {01f8bd55-9017-438b-85ec-7c15d2b35cdc}
--- a/browser/components/preferences/in-content/containers.xul
+++ b/browser/components/preferences/in-content/containers.xul
@@ -5,17 +5,17 @@
 <!-- Containers panel -->
 
 <script type="application/javascript"
         src="chrome://browser/content/preferences/in-content/containers.js"/>
 
 <hbox hidden="true"
       class="container-header-links"
       data-category="paneContainers">
-  <label class="text-link" id="backContainersLink" data-l10n-id="containers-back-link"/>
+  <label is="text-link" id="backContainersLink" data-l10n-id="containers-back-link"/>
 </hbox>
 
 <hbox id="header-containers"
       class="header"
       hidden="true"
       data-category="paneContainers">
   <html:h1 data-l10n-id="containers-header"/>
 </hbox>
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -101,17 +101,17 @@
                 data-l10n-id="disable-extension" />
       </hbox>
       <hbox align="center">
         <checkbox id="browserContainersCheckbox"
                   class="tail-with-learn-more"
                   data-l10n-id="browser-containers-enabled"
                   preference="privacy.userContext.enabled"
                   onsyncfrompreference="return gMainPane.readBrowserContainersCheckbox();"/>
-        <label id="browserContainersLearnMore" class="learnMore text-link" data-l10n-id="browser-containers-learn-more"/>
+        <label id="browserContainersLearnMore" is="text-link" class="learnMore" data-l10n-id="browser-containers-learn-more"/>
         <spacer flex="1"/>
         <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
         <hbox>
           <button id="browserContainersSettings"
                   class="accessory-button"
                   data-l10n-id="browser-containers-settings"
                   search-l10n-ids="containers-add-button.label,
                     containers-preferences-button.label,
@@ -394,17 +394,17 @@
 
 
 <!-- DRM Content -->
 <groupbox id="drmGroup" data-category="paneGeneral" data-subcategory="drm" hidden="true">
   <label><html:h2 data-l10n-id="drm-content-header"/></label>
   <hbox align="center">
     <checkbox id="playDRMContent" preference="media.eme.enabled"
               class="tail-with-learn-more" data-l10n-id="play-drm-content" />
-    <label id="playDRMContentLink" class="learnMore text-link" data-l10n-id="play-drm-content-learn-more"/>
+    <label id="playDRMContentLink" class="learnMore" data-l10n-id="play-drm-content-learn-more" is="text-link"/>
   </hbox>
 </groupbox>
 
 #ifdef HAVE_SHELL_SERVICE
   <stringbundle id="bundleShell" src="chrome://browser/locale/shellservice.properties"/>
   <stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
 #endif
 
@@ -504,25 +504,25 @@
         <label data-l10n-id="update-otherInstanceHandlingUpdates"></label>
         <spacer flex="1"/>
         <button data-l10n-id="update-checkForUpdatesButton"
                 disabled="true"/>
       </hbox>
       <hbox id="manualUpdate" align="start">
         <image class="face-sad"/>
         <description flex="1" data-l10n-id="update-manual">
-          <label id="manualLink" class="text-link" data-l10n-name="manual-link"/>
+          <label id="manualLink" data-l10n-name="manual-link" is="text-link"/>
         </description>
         <spacer flex="1"/>
         <button data-l10n-id="update-checkForUpdatesButton"
                 disabled="true"/>
       </hbox>
       <hbox id="unsupportedSystem" align="start">
         <description flex="1" data-l10n-id="update-unsupported">
-          <label id="unsupportedLink" class="learnMore text-link" data-l10n-name="unsupported-link"></label>
+          <label id="unsupportedLink" class="learnMore" data-l10n-name="unsupported-link" is="text-link"></label>
         </description>
         <spacer flex="1"/>
         <button data-l10n-id="update-checkForUpdatesButton"
                 disabled="true"/>
       </hbox>
       <hbox id="restarting" align="start">
         <image class="update-throbber"/><label data-l10n-id="update-restarting"></label>
         <spacer flex="1"/>
@@ -570,17 +570,17 @@
 <groupbox id="performanceGroup" data-category="paneGeneral" hidden="true">
   <label class="search-header" hidden="true"><html:h2 data-l10n-id="performance-title"/></label>
 
   <hbox align="center">
     <checkbox id="useRecommendedPerformanceSettings"
               class="tail-with-learn-more"
               data-l10n-id="performance-use-recommended-settings-checkbox"
               preference="browser.preferences.defaultPerformanceSettings.enabled"/>
-    <label id="performanceSettingsLearnMore" class="learnMore text-link" data-l10n-id="performance-settings-learn-more"/>
+    <label id="performanceSettingsLearnMore" class="learnMore" data-l10n-id="performance-settings-learn-more" is="text-link"/>
   </hbox>
   <description class="indent tip-caption" data-l10n-id="performance-use-recommended-settings-desc"/>
 
   <vbox id="performanceSettings" class="indent" hidden="true">
     <checkbox id="allowHWAccel"
               data-l10n-id="performance-allow-hw-accel"
               preference="layers.acceleration.disabled"/>
     <hbox align="center">
@@ -635,17 +635,17 @@
   <checkbox id="searchStartTyping"
             data-l10n-id="browsing-search-on-start-typing"
             preference="accessibility.typeaheadfind"/>
   <hbox align="center" data-subcategory="cfr">
     <checkbox id="cfrRecommendations"
             class="tail-with-learn-more"
             data-l10n-id="browsing-cfr-recommendations"
             preference="browser.newtabpage.activity-stream.asrouter.userprefs.cfr"/>
-    <label id="cfrLearnMore" class="learnMore text-link" data-l10n-id="browsing-cfr-recommendations-learn-more"/>
+    <label id="cfrLearnMore" class="learnMore" data-l10n-id="browsing-cfr-recommendations-learn-more" is="text-link"/>
   </hbox>
 </groupbox>
 
 <hbox id="networkProxyCategory"
       class="subcategory"
       hidden="true"
       data-category="paneGeneral">
   <html:h1 data-l10n-id="network-settings-title"/>
@@ -654,17 +654,17 @@
 <!-- Network Settings-->
 <groupbox id="connectionGroup" data-category="paneGeneral" hidden="true">
   <label class="search-header" hidden="true"><html:h2 data-l10n-id="network-settings-title"/></label>
 
   <hbox align="center">
     <hbox align="center" flex="1">
       <description id="connectionSettingsDescription" control="connectionSettings"/>
       <spacer width="5"/>
-      <label id="connectionSettingsLearnMore" class="learnMore text-link"
+      <label id="connectionSettingsLearnMore" class="learnMore" is="text-link"
         data-l10n-id="network-proxy-connection-learn-more">
       </label>
       <separator orient="vertical"/>
     </hbox>
 
     <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
     <hbox>
       <button id="connectionSettings"
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -138,26 +138,26 @@
           <image class="category-icon"/>
           <label class="category-name" flex="1" data-l10n-id="pane-sync-title"></label>
         </richlistitem>
       </richlistbox>
 
       <spacer flex="1"/>
 
       <hbox class="sidebar-footer-button" pack="center">
-        <label id="addonsButton" class="text-link">
+        <label id="addonsButton" is="text-link">
           <hbox align="center">
             <image class="sidebar-footer-icon addons-icon"/>
             <label class="sidebar-footer-label" flex="1" data-l10n-id="addons-button-label"></label>
           </hbox>
         </label>
       </hbox>
 
       <hbox class="sidebar-footer-button help-button" pack="center">
-        <label id="helpButton" class="text-link">
+        <label id="helpButton" is="text-link">
           <hbox align="center">
             <image class="sidebar-footer-icon help-icon"/>
             <label class="sidebar-footer-label" flex="1" data-l10n-id="help-button-label"></label>
           </hbox>
         </label>
       </hbox>
     </vbox>
 
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -20,17 +20,17 @@
 <groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" aria-describedby="contentBlockingDescription">
   <label id="contentBlockingHeader"><html:h2 data-l10n-id="content-blocking-header"/></label>
   <vbox data-subcategory="trackingprotection">
     <hbox align="start">
       <image id="trackingProtectionShield"/>
       <vbox flex="1">
         <description class="description-with-side-element">
           <html:span id="contentBlockingDescription" class="tail-with-learn-more" data-l10n-id="content-blocking-description"></html:span>
-          <label id="contentBlockingLearnMore" class="learnMore text-link" data-l10n-id="content-blocking-learn-more"/>
+          <label id="contentBlockingLearnMore" class="learnMore" data-l10n-id="content-blocking-learn-more" is="text-link"/>
         </description>
       </vbox>
       <vbox>
         <!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
         <hbox>
           <button id="trackingProtectionExceptions"
                   class="accessory-button"
                   flex="1"
@@ -102,17 +102,17 @@
                 <vbox class="content-blocking-warning">
                   <vbox class="indent">
                     <hbox>
                       <image class="content-blocking-warning-image"/>
                       <label class="content-blocking-warning-title" data-l10n-id="content-blocking-warning-title"/>
                     </hbox>
                     <description class="indent">
                       <html:span class="tail-with-learn-more" data-l10n-id="content-blocking-warning-description"></html:span>
-                      <label class="text-link content-blocking-warning-learn-how" data-l10n-id="content-blocking-learn-how"/>
+                      <label class="content-blocking-warning-learn-how" data-l10n-id="content-blocking-learn-how" is="text-link"/>
                     </description>
                   </vbox>
                 </vbox>
               </vbox>
             </vbox>
           </vbox>
         <vbox id="contentBlockingOptionCustom" class="tracking-protection-ui content-blocking-category">
           <hbox>
@@ -143,17 +143,17 @@
                         <menuitem data-l10n-id="content-blocking-option-private" value="private"/>
                         <menuitem data-l10n-id="content-blocking-tracking-protection-option-all-windows" value="always"/>
                       </menupopup>
                     </menulist>
                   </vbox>
                 </hbox>
                 <label id="changeBlockListLink"
                        data-l10n-id="content-blocking-tracking-protection-change-block-list"
-                       class="text-link"
+                       is="text-link"
                        search-l10n-ids="blocklist-window.title, blocklist-description, blocklist-button-cancel.label, blocklist-button-ok.label"/>
                 <hbox class="reject-trackers-ui custom-option">
                   <checkbox id="contentBlockingBlockCookiesCheckbox"
                             class="content-blocking-checkbox" flex="1"
                             data-l10n-id="content-blocking-cookies-label"
                             aria-describedby="contentBlockingCustomDesc"
                             preference="network.cookie.cookieBehavior"
                             onsyncfrompreference="return gPrivacyPane.readBlockCookies();"
@@ -192,28 +192,28 @@
               <vbox class="content-blocking-warning">
                 <vbox class="indent">
                   <hbox>
                     <image class="content-blocking-warning-image"/>
                     <label class="content-blocking-warning-title" data-l10n-id="content-blocking-warning-title"/>
                   </hbox>
                   <description class="indent">
                     <html:span class="tail-with-learn-more" data-l10n-id="content-blocking-warning-description"></html:span>
-                    <label class="text-link content-blocking-warning-learn-how" data-l10n-id="content-blocking-learn-how"/>
+                    <label class="content-blocking-warning-learn-how" data-l10n-id="content-blocking-learn-how" is="text-link"/>
                   </description>
                 </vbox>
               </vbox>
             </vbox>
           </vbox>
         </vbox>
       </radiogroup>
     </vbox>
     <vbox id="doNotTrackLearnMoreBox">
       <label><label class="tail-with-learn-more" data-l10n-id="do-not-track-description" id="doNotTrackDesc"></label><label
-      class="learnMore text-link" href="https://www.mozilla.org/dnt"
+      class="learnMore" is="text-link" href="https://www.mozilla.org/dnt"
       data-l10n-id="do-not-track-learn-more"></label></label>
       <radiogroup id="doNotTrackRadioGroup" aria-labelledby="doNotTrackDesc" preference="privacy.donottrackheader.enabled">
         <radio value="true" data-l10n-id="do-not-track-option-always"/>
         <radio value="false" data-l10n-id="do-not-track-option-default-content-blocking-known"/>
       </radiogroup>
     </vbox>
   </vbox>
 </groupbox>
@@ -222,17 +222,17 @@
 <groupbox id="siteDataGroup" data-category="panePrivacy" hidden="true" aria-describedby="totalSiteDataSize">
   <label><html:h2 data-l10n-id="sitedata-header"/></label>
 
   <hbox data-subcategory="sitedata" align="baseline">
     <vbox flex="1">
       <description class="description-with-side-element" flex="1">
         <html:span id="totalSiteDataSize" class="tail-with-learn-more"></html:span>
         <label id="siteDataLearnMoreLink"
-          class="learnMore text-link" data-l10n-id="sitedata-learn-more"/>
+          class="learnMore" is="text-link" data-l10n-id="sitedata-learn-more"/>
       </description>
       <hbox flex="1" id="deleteOnCloseNote" class="info-panel">
         <description flex="1" data-l10n-id="sitedata-delete-on-close-private-browsing" />
       </hbox>
       <hbox id="keepRow"
             align="center">
         <checkbox id="deleteOnClose"
                   data-l10n-id="sitedata-delete-on-close"
@@ -447,17 +447,17 @@
   <label><html:h2 data-l10n-id="addressbar-header"/></label>
   <label id="locationBarSuggestionLabel" data-l10n-id="addressbar-suggest"/>
   <checkbox id="historySuggestion" data-l10n-id="addressbar-locbar-history-option"
             preference="browser.urlbar.suggest.history"/>
   <checkbox id="bookmarkSuggestion" data-l10n-id="addressbar-locbar-bookmarks-option"
             preference="browser.urlbar.suggest.bookmark"/>
   <checkbox id="openpageSuggestion" data-l10n-id="addressbar-locbar-openpage-option"
             preference="browser.urlbar.suggest.openpage"/>
-  <label class="text-link" id="openSearchEnginePreferences"
+  <label id="openSearchEnginePreferences" is="text-link"
          data-l10n-id="addressbar-suggestions-settings"/>
 </groupbox>
 
 <hbox id="permissionsCategory"
       class="subcategory"
       hidden="true"
       data-category="panePrivacy">
   <html:h1 data-l10n-id="permissions-header"/>
@@ -541,17 +541,18 @@
     <hbox id="notificationSettingsRow" align="center" role="group" aria-labelledby="notificationPermissionsLabel">
       <description flex="1">
         <image class="desktop-notification-icon permission-icon" />
         <separator orient="vertical" class="thin"/>
         <label id="notificationPermissionsLabel"
                class="tail-with-learn-more"
                data-l10n-id="permissions-notification"/>
         <label id="notificationPermissionsLearnMore"
-               class="learnMore text-link"
+               class="learnMore"
+               is="text-link"
                data-l10n-id="permissions-notification-link"/>
       </description>
       <hbox pack="end">
         <button id="notificationSettingsButton"
                 class="accessory-button"
                 data-l10n-id="permissions-notification-settings"
                 search-l10n-ids="
                   permissions-remove.label,
@@ -636,17 +637,17 @@
     </hbox>
   </hbox>
 
   <vbox id="a11yPermissionsBox">
     <hbox flex="1" align="center">
       <checkbox id="a11yPrivacyCheckbox" class="tail-with-learn-more"
                 data-l10n-id="permissions-a11y-privacy-checkbox"
                 oncommand="return gPrivacyPane.updateA11yPrefs(this.checked)"/>
-      <label id="a11yLearnMoreLink" class="learnMore text-link"
+      <label id="a11yLearnMoreLink" class="learnMore" is="text-link"
              data-l10n-id="permissions-a11y-privacy-link"/>
     </hbox>
   </vbox>
 
 </groupbox>
 
 <!-- Firefox Data Collection and Use -->
 #ifdef MOZ_DATA_REPORTING
@@ -658,45 +659,45 @@
 </hbox>
 
 <groupbox id="dataCollectionGroup" data-category="panePrivacy" hidden="true">
   <label class="search-header" hidden="true"><html:h2 data-l10n-id="collection-header"/></label>
 
   <description>
     <label class="tail-with-learn-more" data-l10n-id="collection-description"/>
     <label id="dataCollectionPrivacyNotice"
-           class="learnMore text-link"
+           class="learnMore" is="text-link"
            data-l10n-id="collection-privacy-notice"/>
   </description>
   <vbox data-subcategory="reports">
     <description flex="1">
       <checkbox id="submitHealthReportBox"
                 data-l10n-id="collection-health-report"
                 class="tail-with-learn-more"/>
       <label id="FHRLearnMore"
-             class="learnMore text-link"
+             class="learnMore" is="text-link"
              data-l10n-id="collection-health-report-link"/>
       <vbox class="indent">
         <hbox align="center">
           <checkbox id="optOutStudiesEnabled"
                     class="tail-with-learn-more"
                     data-l10n-id="collection-studies"/>
           <label id="viewShieldStudies"
                  href="about:studies"
                  useoriginprincipal="true"
-                 class="learnMore text-link"
+                 class="learnMore" is="text-link"
                  data-l10n-id="collection-studies-link"/>
         </hbox>
 
         <hbox align="center">
           <checkbox id="addonRecommendationEnabled"
                     class="tail-with-learn-more"
                     data-l10n-id="addon-recommendations"/>
           <label id="addonRecommendationLearnMore"
-                 class="learnMore text-link"
+                 class="learnMore" is="text-link"
                  data-l10n-id="addon-recommendations-link"/>
         </hbox>
       </vbox>
     </description>
 #ifndef MOZ_TELEMETRY_REPORTING
   <description id="TelemetryDisabledDesc"
     class="indent tip-caption" control="telemetryGroup"
     data-l10n-id="collection-health-report-disabled"/>
@@ -705,17 +706,17 @@
 #ifdef MOZ_CRASHREPORTER
     <hbox align="center">
       <checkbox id="automaticallySubmitCrashesBox"
                 class="tail-with-learn-more"
                 preference="browser.crashReports.unsubmittedCheck.autoSubmit2"
                 data-l10n-id="collection-backlogged-crash-reports"
                 flex="1"/>
       <label id="crashReporterLearnMore"
-              class="learnMore text-link" data-l10n-id="collection-backlogged-crash-reports-link"/>
+              class="learnMore" is="text-link" data-l10n-id="collection-backlogged-crash-reports-link"/>
     </hbox>
 #endif
   </vbox>
 </groupbox>
 #endif
 
 <hbox id="securityCategory"
       class="subcategory"
@@ -727,17 +728,17 @@
 <!-- addons, forgery (phishing) UI Security -->
 <groupbox id="browsingProtectionGroup" data-category="panePrivacy" hidden="true">
   <label><html:h2 data-l10n-id="security-browsing-protection"/></label>
   <hbox align = "center">
     <checkbox id="enableSafeBrowsing"
               data-l10n-id="security-enable-safe-browsing"
               class="tail-with-learn-more"/>
     <label id="enableSafeBrowsingLearnMore"
-           class="learnMore text-link" data-l10n-id="security-enable-safe-browsing-link"/>
+           class="learnMore" is="text-link" data-l10n-id="security-enable-safe-browsing-link"/>
   </hbox>
   <vbox class="indent">
     <checkbox id="blockDownloads"
               data-l10n-id="security-block-downloads"/>
     <checkbox id="blockUncommonUnwanted"
               data-l10n-id="security-block-uncommon-software"/>
   </vbox>
 </groupbox>
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content/search.xul
@@ -73,12 +73,12 @@
         <spacer flex="1"/>
         <button id="removeEngineButton"
                 class="searchEngineAction"
                 data-l10n-id="search-remove-engine"
                 disabled="true"
                 />
       </hbox>
       <hbox id="addEnginesBox" pack="start">
-        <label id="addEngines" class="text-link" data-l10n-id="search-find-more-link"></label>
+        <label id="addEngines" data-l10n-id="search-find-more-link" is="text-link"></label>
       </hbox>
     </groupbox>
     ]]></box>
--- a/browser/components/preferences/in-content/sync.xul
+++ b/browser/components/preferences/in-content/sync.xul
@@ -180,20 +180,20 @@
                 data-l10n-id="sync-device-name-cancel"
                 hidden="true"/>
         <button id="fxaSaveChangeDeviceName"
                 data-l10n-id="sync-device-name-save"
                 hidden="true"/>
       </hbox>
     </groupbox>
     <vbox align="start">
-      <label id="mobilePromo-singledevice"
-             class="text-link fxaMobilePromo" data-l10n-id="sync-mobilepromo-single"/>
-      <label id="mobilePromo-multidevice"
-             class="text-link fxaMobilePromo" data-l10n-id="sync-mobilepromo-multi"/>
+      <label id="mobilePromo-singledevice" is="text-link"
+             class="fxaMobilePromo" data-l10n-id="sync-mobilepromo-single"/>
+      <label id="mobilePromo-multidevice" is="text-link"
+             class="fxaMobilePromo" data-l10n-id="sync-mobilepromo-multi"/>
     </vbox>
     <vbox id="tosPP-small" align="start">
-      <label id="tosPP-small-ToS" class="text-link" data-l10n-id="sync-tos-link"/>
-      <label id="tosPP-small-PP" class="text-link" data-l10n-id="sync-fxa-privacy-notice"/>
+      <label id="tosPP-small-ToS" is="text-link" data-l10n-id="sync-tos-link"/>
+      <label id="tosPP-small-PP" is="text-link" data-l10n-id="sync-fxa-privacy-notice"/>
     </vbox>
   </vbox>
 </deck>
 ]]></box>
--- a/browser/components/preferences/in-content/tests/browser_advanced_update.js
+++ b/browser/components/preferences/in-content/tests/browser_advanced_update.js
@@ -9,41 +9,37 @@ const uuidGenerator = Cc["@mozilla.org/u
 
 const mockUpdateManager = {
   contractId: "@mozilla.org/updates/update-manager;1",
 
   _mockClassId: uuidGenerator.generateUUID(),
 
   _originalClassId: "",
 
-  _originalFactory: null,
-
   QueryInterface: ChromeUtils.generateQI([Ci.nsIUpdateManager]),
 
   createInstance(outer, iiD) {
     if (outer) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
     return this.QueryInterface(iiD);
   },
 
   register() {
     let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
     if (!registrar.isCIDRegistered(this._mockClassId)) {
       this._originalClassId = registrar.contractIDToCID(this.contractId);
-      this._originalFactory = Cm.getClassObject(Cc[this.contractId], Ci.nsIFactory);
-      registrar.unregisterFactory(this._originalClassId, this._originalFactory);
       registrar.registerFactory(this._mockClassId, "Unregister after testing", this.contractId, this);
     }
   },
 
   unregister() {
     let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
     registrar.unregisterFactory(this._mockClassId, this);
-    registrar.registerFactory(this._originalClassId, "", this.contractId, this._originalFactory);
+    registrar.registerFactory(this._originalClassId, "", this.contractId, null);
   },
 
   get updateCount() {
     return this._updates.length;
   },
 
   getUpdateAt(index) {
     return this._updates[index];
rename from browser/components/protocolhandler/WebProtocolHandlerRegistrar.js
rename to browser/components/protocolhandler/WebProtocolHandlerRegistrar.jsm
--- a/browser/components/protocolhandler/WebProtocolHandlerRegistrar.js
+++ b/browser/components/protocolhandler/WebProtocolHandlerRegistrar.jsm
@@ -1,15 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
 
+var EXPORTED_SYMBOLS = ["WebProtocolHandlerRegistrar"];
+
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties";
 
 function WebProtocolHandlerRegistrar() {
 }
 
 WebProtocolHandlerRegistrar.prototype = {
   get stringBundle() {
@@ -141,18 +142,13 @@ WebProtocolHandlerRegistrar.prototype = 
     let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
     notificationBox.appendNotification(message,
                                        notificationValue,
                                        notificationIcon,
                                        notificationBox.PRIORITY_INFO_LOW,
                                        [addButton]);
   },
 
-  classID: Components.ID("{efbd7b87-9b15-4684-abf0-dc2679daadb1}"),
-
   /**
    * See nsISupports
    */
   QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProtocolHandlerRegistrar]),
 };
-
-this.NSGetFactory =
-  XPCOMUtils.generateNSGetFactory([WebProtocolHandlerRegistrar]);
new file mode 100644
--- /dev/null
+++ b/browser/components/protocolhandler/components.conf
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{efbd7b87-9b15-4684-abf0-dc2679daadb1}',
+        'contract_ids': ['@mozilla.org/embeddor.implemented/web-protocol-handler-registrar;1'],
+        'jsm': 'resource:///modules/WebProtocolHandlerRegistrar.jsm',
+        'constructor': 'WebProtocolHandlerRegistrar',
+        'processes': ProcessSelector.MAIN_PROCESS_ONLY,
+    },
+]
--- a/browser/components/protocolhandler/moz.build
+++ b/browser/components/protocolhandler/moz.build
@@ -2,14 +2,18 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOCHITEST_MANIFESTS += ['test/mochitest.ini']
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 
-EXTRA_COMPONENTS += [
-    'WebProtocolHandlerRegistrar.js',
+EXTRA_JS_MODULES += [
+    'WebProtocolHandlerRegistrar.jsm',
+]
+
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 with Files('**'):
     BUG_COMPONENT = ('Firefox', 'General')
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -181,18 +181,17 @@ ContentRestoreInternal.prototype = {
       webNavigation.setCurrentURI(Services.io.newURI("about:blank"));
     }
 
     try {
       if (loadArguments) {
         // If the load was started in another process, and the in-flight channel
         // was redirected into this process, resume that load within our process.
         if (loadArguments.redirectLoadSwitchId) {
-          webNavigation.resumeRedirectedLoad(loadArguments.redirectLoadSwitchId,
-                                             loadArguments.redirectHistoryIndex);
+          webNavigation.resumeRedirectedLoad(loadArguments.redirectLoadSwitchId);
           return true;
         }
 
         // A load has been redirected to a new process so get history into the
         // same state it was before the load started then trigger the load.
         // Referrer information is now stored as a referrerInfo property. We
         // should also cope with the old format of passing `referrer` and
         // `referrerPolicy` separately.
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -43,17 +43,19 @@ const SCREEN_EDGE_SLOP = 8;
 
 // global notifications observed
 const OBSERVING = [
   "browser-window-before-show", "domwindowclosed",
   "quit-application-granted", "browser-lastwindow-close-granted",
   "quit-application", "browser:purge-session-history",
   "browser:purge-session-history-for-domain",
   "idle-daily", "clear-origin-attributes-data",
-  "http-on-may-change-process",
+  "http-on-examine-response",
+  "http-on-examine-merged-response",
+  "http-on-examine-cached-response",
 ];
 
 // XUL Window properties to (re)store
 // Restored in restoreDimensions()
 const WINDOW_ATTRIBUTES = ["width", "height", "screenX", "screenY", "sizemode"];
 
 // Hideable window features to (re)store
 // Restored in restoreWindowFeatures()
@@ -807,18 +809,20 @@ var SessionStoreInternal = {
         let userContextId = 0;
         try {
           userContextId = JSON.parse(aData).userContextId;
         } catch (e) {}
         if (userContextId) {
           this._forgetTabsWithUserContextId(userContextId);
         }
         break;
-      case "http-on-may-change-process":
-        this.onMayChangeProcess(aSubject);
+      case "http-on-examine-response":
+      case "http-on-examine-cached-response":
+      case "http-on-examine-merged-response":
+        this.onExamineResponse(aSubject);
         break;
     }
   },
 
   /**
    * This method handles incoming messages sent by the session store content
    * script via the Frame Message Manager or Parent Process Message Manager,
    * and thus enables communication with OOP tabs.
@@ -2277,18 +2281,16 @@ var SessionStoreInternal = {
   },
 
   /**
    * Perform a destructive process switch into a distinct process.
    * This method is asynchronous, as it requires multiple calls into content
    * processes.
    */
   async _doProcessSwitch(aBrowser, aRemoteType, aChannel, aSwitchId) {
-    debug(`[process-switch]: performing switch from ${aBrowser.remoteType} to ${aRemoteType}`);
-
     // Don't try to switch tabs before delayed startup is completed.
     await aBrowser.ownerGlobal.delayedStartupPromise;
 
     // Perform a navigateAndRestore to trigger the process switch.
     let tab = aBrowser.ownerGlobal.gBrowser.getTabForBrowser(aBrowser);
     let loadArguments = {
       newFrameloader: true,  // Switch even if remoteType hasn't changed.
       remoteType: aRemoteType,  // Don't derive remoteType to switch to.
@@ -2302,113 +2304,73 @@ var SessionStoreInternal = {
     // If the process switch seems to have failed, send an error over to our
     // caller, to give it a chance to kill our channel.
     if (aBrowser.remoteType != aRemoteType ||
         !aBrowser.frameLoader || !aBrowser.frameLoader.tabParent) {
       throw Cr.NS_ERROR_FAILURE;
     }
 
     // Tell our caller to redirect the load into this newly created process.
-    let tabParent = aBrowser.frameLoader.tabParent;
-    debug(`[process-switch]: new tabID: ${tabParent.tabId}`);
-    return tabParent;
+    return aBrowser.frameLoader.tabParent;
   },
 
   // Examine the channel response to see if we should change the process
   // performing the given load.
-  onMayChangeProcess(aChannel) {
-    if (!E10SUtils.useHttpResponseProcessSelection() &&
-        !E10SUtils.useCrossOriginOpenerPolicy()) {
+  onExamineResponse(aChannel) {
+    if (!E10SUtils.useHttpResponseProcessSelection()) {
       return;
     }
 
     if (!aChannel.isDocument || !aChannel.loadInfo) {
       return; // Not a document load.
     }
 
-    // Check that this is a toplevel document load.
-    let cpType = aChannel.loadInfo.externalContentPolicyType;
-    let toplevel = cpType == Ci.nsIContentPolicy.TYPE_DOCUMENT;
-    if (!toplevel) {
-      debug(`[process-switch]: non-toplevel - ignoring`);
-      return;
-    }
-
-    // Check that the document has a corresponding BrowsingContext.
-    let browsingContext = toplevel
-        ? aChannel.loadInfo.browsingContext
-        : aChannel.loadInfo.frameBrowsingContext;
+    let browsingContext = aChannel.loadInfo.browsingContext;
     if (!browsingContext) {
-      debug(`[process-switch]: no BrowsingContext - ignoring`);
-      return;
+      return; // Not loading in a browsing context.
+    }
+
+    if (browsingContext.parent) {
+      return; // Not a toplevel load, can't flip procs.
     }
 
     // Get principal for a document already loaded in the BrowsingContext.
     let currentPrincipal = null;
     if (browsingContext.currentWindowGlobal) {
       currentPrincipal = browsingContext.currentWindowGlobal.documentPrincipal;
     }
 
-    // Ensure we have an nsIParentChannel listener for a remote load.
-    let parentChannel;
-    try {
-      parentChannel = aChannel.notificationCallbacks
-                              .getInterface(Ci.nsIParentChannel);
-    } catch (e) {
-      debug(`[process-switch]: No nsIParentChannel callback - ignoring`);
-      return;
-    }
-
-    // Ensure we have a nsITabParent for our remote load.
-    let tabParent;
-    try {
-      tabParent = parentChannel.QueryInterface(Ci.nsIInterfaceRequestor)
-                               .getInterface(Ci.nsITabParent);
-    } catch (e) {
-      debug(`[process-switch]: No nsITabParent for channel - ignoring`);
-      return;
-    }
-
-    // Ensure we're loaded in a regular tabbrowser environment, and can swap processes.
+    let parentChannel = aChannel.notificationCallbacks
+                                .getInterface(Ci.nsIParentChannel);
+    if (!parentChannel) {
+      return; // Not an actor channel
+    }
+
+    let tabParent = parentChannel.QueryInterface(Ci.nsIInterfaceRequestor)
+                                 .getInterface(Ci.nsITabParent);
+    if (!tabParent || !tabParent.ownerElement) {
+      console.warn("warning: Missing tabParent");
+      return; // Not an embedded browsing context
+    }
+
     let browser = tabParent.ownerElement;
-    if (!browser) {
-      debug(`[process-switch]: TabParent has no ownerElement - ignoring`);
-      return;
-    }
-
-    let tabbrowser = browser.ownerGlobal.gBrowser;
-    if (!tabbrowser) {
-      debug(`[process-switch]: cannot find tabbrowser for loading tab - ignoring`);
-      return;
-    }
-
-    let tab = tabbrowser.getTabForBrowser(browser);
-    if (!tab) {
-      debug(`[process-switch]: not a normal tab, so cannot swap processes - ignoring`);
-      return;
-    }
-
-    // Determine the process type the load should be performed in.
+    if (browser.tagName !== "browser") {
+      console.warn("warning: Not a xul:browser element:", browser.tagName);
+      return; // Not a vanilla xul:browser element performing embedding.
+    }
+
     let resultPrincipal =
       Services.scriptSecurityManager.getChannelResultPrincipal(aChannel);
+    let useRemoteTabs = browser.ownerGlobal.gMultiProcessBrowser;
     let remoteType = E10SUtils.getRemoteTypeForPrincipal(resultPrincipal,
-                                                         true,
+                                                         useRemoteTabs,
                                                          browser.remoteType,
                                                          currentPrincipal);
-    if (browser.remoteType == remoteType &&
-        (!E10SUtils.useCrossOriginOpenerPolicy() ||
-         !aChannel.hasCrossOriginOpenerPolicyMismatch())) {
-      debug(`[process-switch]: type (${remoteType}) is compatible - ignoring`);
-      return;
-    }
-
-    if (remoteType == E10SUtils.NOT_REMOTE ||
-        browser.remoteType == E10SUtils.NOT_REMOTE) {
-      debug(`[process-switch]: non-remote source/target - ignoring`);
-      return;
+    if (browser.remoteType == remoteType) {
+      return; // Already in compatible process.
     }
 
     // ------------------------------------------------------------------------
     // DANGER ZONE: Perform a process switch into the new process. This is
     // destructive.
     // ------------------------------------------------------------------------
     let identifier = ++this._switchIdMonotonic;
     let tabPromise = this._doProcessSwitch(browser, remoteType,
@@ -3264,24 +3226,16 @@ var SessionStoreInternal = {
       restoreContentReason: RESTORE_TAB_CONTENT_REASON.NAVIGATE_AND_RESTORE,
     };
 
     if (historyIndex >= 0) {
       tabState.index = historyIndex + 1;
       tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length));
     } else {
       options.loadArguments = loadArguments;
-
-      // If we're resuming a load which has been redirected from another
-      // process, record the history index which is currently being requested.
-      // It has to be offset by 1 to get back to native history indices from
-      // SessionStore history indicies.
-      if (loadArguments.redirectLoadSwitchId) {
-        loadArguments.redirectHistoryIndex = tabState.requestedIndex - 1;
-      }
     }
 
     // Need to reset restoring tabs.
     if (TAB_STATE_FOR_BROWSER.has(tab.linkedBrowser)) {
       this._resetLocalTabRestoringState(tab);
     }
 
     // Restore the state into the tab.
@@ -3340,17 +3294,17 @@ var SessionStoreInternal = {
     // home pages then we'll end up overwriting all of them. Otherwise we'll
     // just close the tabs that match home pages. Tabs with the about:blank
     // URI will always be overwritten.
     let homePages = ["about:blank"];
     let removableTabs = [];
     let tabbrowser = aWindow.gBrowser;
     let startupPref = this._prefBranch.getIntPref("startup.page");
     if (startupPref == 1)
-      homePages = homePages.concat(HomePage.get(aWindow).split("|"));
+      homePages = homePages.concat(HomePage.get().split("|"));
 
     for (let i = tabbrowser._numPinnedTabs; i < tabbrowser.tabs.length; i++) {
       let tab = tabbrowser.tabs[i];
       if (homePages.includes(tab.linkedBrowser.currentURI.spec)) {
         removableTabs.push(tab);
       }
     }
 
--- a/browser/components/sessionstore/TabState.jsm
+++ b/browser/components/sessionstore/TabState.jsm
@@ -179,18 +179,14 @@ var TabStateInternal = {
 
         if (value.hasOwnProperty("userContextId")) {
           tabData.userContextId = value.userContextId;
         }
 
         if (value.hasOwnProperty("index")) {
           tabData.index = value.index;
         }
-
-        if (value.hasOwnProperty("requestedIndex")) {
-          tabData.requestedIndex = value.requestedIndex;
-        }
       } else {
         tabData[key] = value;
       }
     }
   },
 };
--- a/browser/components/shell/nsWindowsShellService.cpp
+++ b/browser/components/shell/nsWindowsShellService.cpp
@@ -16,17 +16,16 @@
 #include "nsIPrefLocalizedString.h"
 #include "nsIServiceManager.h"
 #include "nsIStringBundle.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsShellService.h"
 #include "nsIProcess.h"
 #include "nsICategoryManager.h"
-#include "nsBrowserCompsCID.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIWindowsRegKey.h"
 #include "nsUnicharUtils.h"
 #include "nsIURLFormatter.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/WindowsVersion.h"
--- a/browser/components/tests/browser/browser_bug538331.js
+++ b/browser/components/tests/browser/browser_bug538331.js
@@ -260,17 +260,17 @@ function testDefaultArgs() {
     if (Services.prefs.prefHasUserValue(PREF_POSTUPDATE)) {
       Services.prefs.clearUserPref(PREF_POSTUPDATE);
     }
   }
 
   testShowNotification();
 }
 
-// nsBrowserGlue.js _showUpdateNotification notification tests
+// BrowserGlue.jsm _showUpdateNotification notification tests
 const BG_NOTIFY_TESTS = [
   {
     description: "'silent showNotification' actions should not display a notification",
     actions: "silent showNotification",
   }, {
     description: "'showNotification' for actions should display a notification",
     actions: "showNotification",
   }, {
@@ -287,17 +287,17 @@ const BG_NOTIFY_TESTS = [
     notificationText: "notification text",
     notificationURL: DEFAULT_UPDATE_URL,
     notificationButtonLabel: "button label",
     notificationButtonAccessKey: "b",
   },
 ];
 
 // Test showing a notification after an update
-// _showUpdateNotification in nsBrowserGlue.js
+// _showUpdateNotification in BrowserGlue.jsm
 function testShowNotification() {
   // Catches any windows opened by these tests (e.g. alert windows) and closes
   // them
   gWindowCatcher.start();
 
   for (let i = 0; i < BG_NOTIFY_TESTS.length; i++) {
     let testCase = BG_NOTIFY_TESTS[i];
     ok(true, "Test showNotification " + (i + 1) + ": " + testCase.description);
--- a/browser/components/tests/startupRecorder.js
+++ b/browser/components/tests/startupRecorder.js
@@ -74,17 +74,17 @@ startupRecorder.prototype = {
       }),
     };
   },
 
   observe(subject, topic, data) {
     if (topic == "app-startup") {
       // We can't ensure our observer will be called first or last, so the list of
       // topics we observe here should avoid the topics used to trigger things
-      // during startup (eg. the topics observed by nsBrowserGlue.js).
+      // during startup (eg. the topics observed by BrowserGlue.jsm).
       let topics = [
         "profile-do-change", // This catches stuff loaded during app-startup
         "toplevel-window-ready", // Catches stuff from final-ui-startup
         "image-loading",
         "image-drawing",
         firstPaintNotification,
         "sessionstore-windows-restored",
       ];
--- a/browser/components/translation/content/translation-notification.js
+++ b/browser/components/translation/content/translation-notification.js
@@ -10,17 +10,17 @@ class MozTranslationNotification extends
       <hbox anonid="details" align="center" flex="1">
         <image class="translate-infobar-element messageImage"/>
         <panel anonid="welcomePanel" class="translation-welcome-panel" type="arrow" align="start">
           <image class="translation-welcome-logo"/>
           <vbox flex="1" class="translation-welcome-content">
             <description class="translation-welcome-headline" anonid="welcomeHeadline"/>
             <description class="translation-welcome-body" anonid="welcomeBody"/>
             <hbox align="center">
-              <label anonid="learnMore" class="plain text-link" onclick="openTrustedLinkIn('https://support.mozilla.org/kb/automatic-translation', 'tab'); this.parentNode.parentNode.parentNode.hidePopup();"/>
+              <label anonid="learnMore" class="plain" onclick="openTrustedLinkIn('https://support.mozilla.org/kb/automatic-translation', 'tab'); this.parentNode.parentNode.parentNode.hidePopup();" is="text-link"/>
               <spacer flex="1"/>
               <button class="translate-infobar-element" anonid="thanksButton" onclick="this.parentNode.parentNode.parentNode.hidePopup();"/>
             </hbox>
           </vbox>
         </panel>
         <deck anonid="translationStates" selectedIndex="0">
           <hbox class="translate-offer-box" align="center">
             <label class="translate-infobar-element" value="&translation.thisPageIsIn.label;"/>
--- a/browser/extensions/formautofill/FormAutofillDoorhanger.jsm
+++ b/browser/extensions/formautofill/FormAutofillDoorhanger.jsm
@@ -231,18 +231,17 @@ let FormAutofillDoorhanger = {
    *         popupnotificationcontent
    * @param  {string} message
    *         The localized string for link title.
    * @param  {string} link
    *         Makes it possible to open and highlight a section in preferences
    */
   _appendPrivacyPanelLink(content, message, link) {
     let chromeDoc = content.ownerDocument;
-    let privacyLinkElement = chromeDoc.createXULElement("label");
-    privacyLinkElement.className = "text-link";
+    let privacyLinkElement = chromeDoc.createXULElement("label", {is: "text-link"});
     privacyLinkElement.setAttribute("useoriginprincipal", true);
     privacyLinkElement.setAttribute("href", link || "about:preferences#privacy-form-autofill");
     privacyLinkElement.setAttribute("value", message);
     content.appendChild(privacyLinkElement);
   },
 
   /**
    * Append the description section to the popupnotificationcontent.
--- a/browser/extensions/formautofill/FormAutofillPreferences.jsm
+++ b/browser/extensions/formautofill/FormAutofillPreferences.jsm
@@ -73,25 +73,25 @@ FormAutofillPreferences.prototype = {
     let learnMoreURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "autofill-card-address";
     let formAutofillFragment = document.createDocumentFragment();
     let formAutofillGroupBoxLabel = document.createXULElement("label");
     let formAutofillGroupBoxLabelHeading = document.createElementNS(HTML_NS, "h2");
     let formAutofillGroup = document.createXULElement("vbox");
     let addressAutofill = document.createXULElement("hbox");
     let addressAutofillCheckboxGroup = document.createXULElement("hbox");
     let addressAutofillCheckbox = document.createXULElement("checkbox");
-    let addressAutofillLearnMore = document.createXULElement("label");
+    let addressAutofillLearnMore = document.createXULElement("label", {is: "text-link"});
     let savedAddressesBtn = document.createXULElement("button");
     // Wrappers are used to properly compute the search tooltip positions
     let savedAddressesBtnWrapper = document.createXULElement("hbox");
     let savedCreditCardsBtnWrapper = document.createXULElement("hbox");
 
     savedAddressesBtn.className = "accessory-button";
     addressAutofillCheckbox.className = "tail-with-learn-more";
-    addressAutofillLearnMore.className = "learnMore text-link";
+    addressAutofillLearnMore.className = "learnMore";
 
     formAutofillGroup.id = "formAutofillGroup";
     addressAutofill.id = "addressAutofill";
     addressAutofillLearnMore.id = "addressAutofillLearnMore";
 
     formAutofillGroupBoxLabelHeading.textContent = this.bundle.GetStringFromName("autofillHeader");
 
     addressAutofill.setAttribute("data-subcategory", "address-autofill");
@@ -132,21 +132,21 @@ FormAutofillPreferences.prototype = {
       addressAutofillCheckbox,
       savedAddressesBtn,
     };
 
     if (FormAutofill.isAutofillCreditCardsAvailable) {
       let creditCardAutofill = document.createXULElement("hbox");
       let creditCardAutofillCheckboxGroup = document.createXULElement("hbox");
       let creditCardAutofillCheckbox = document.createXULElement("checkbox");
-      let creditCardAutofillLearnMore = document.createXULElement("label");
+      let creditCardAutofillLearnMore = document.createXULElement("label", {is: "text-link"});
       let savedCreditCardsBtn = document.createXULElement("button");
       savedCreditCardsBtn.className = "accessory-button";
       creditCardAutofillCheckbox.className = "tail-with-learn-more";
-      creditCardAutofillLearnMore.className = "learnMore text-link";
+      creditCardAutofillLearnMore.className = "learnMore";
 
       creditCardAutofill.id = "creditCardAutofill";
       creditCardAutofillLearnMore.id = "creditCardAutofillLearnMore";
 
       creditCardAutofill.setAttribute("data-subcategory", "credit-card-autofill");
       creditCardAutofillCheckbox.setAttribute("label", this.bundle.GetStringFromName("autofillCreditCardsCheckbox"));
       creditCardAutofillLearnMore.textContent = this.bundle.GetStringFromName("learnMoreLabel");
       savedCreditCardsBtn.setAttribute("label", this.bundle.GetStringFromName("savedCreditCardsBtnLabel"));
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pdfjs/components.conf
@@ -0,0 +1,17 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{d0c5195d-e798-49d4-b1d3-9324328b2291}',
+        'contract_ids': [
+            '@mozilla.org/streamconv;1?from=application/pdf&to=*/*',
+            '@mozilla.org/streamconv;1?from=application/pdf&to=text/html',
+        ],
+        'jsm': 'resource:///modules/pdfjs.js',
+        'constructor': 'StreamConverterFactory',
+    },
+]
--- a/browser/extensions/pdfjs/content/PdfJs.jsm
+++ b/browser/extensions/pdfjs/content/PdfJs.jsm
@@ -104,17 +104,17 @@ var PdfJs = {
     PdfjsChromeUtils.init();
     this.initPrefs();
 
     Services.ppmm.sharedData.set("pdfjs.enabled", this.checkEnabled());
   },
 
   earlyInit() {
     // Note: Please keep this in sync with the duplicated logic in
-    // nsBrowserGlue.js.
+    // BrowserGlue.jsm.
     Services.ppmm.sharedData.set("pdfjs.enabled", this.checkEnabled());
   },
 
   initPrefs: function initPrefs() {
     if (this._initialized) {
       return;
     }
     this._initialized = true;
--- a/browser/extensions/pdfjs/moz.build
+++ b/browser/extensions/pdfjs/moz.build
@@ -6,12 +6,15 @@
 
 with Files("**"):
     BUG_COMPONENT = ("Firefox", "PDF Viewer")
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 JAR_MANIFESTS += ['jar.mn']
 
-EXTRA_COMPONENTS += [
+EXTRA_JS_MODULES += [
     'pdfjs.js',
-    'pdfjs.manifest',
 ]
+
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
--- a/browser/extensions/pdfjs/pdfjs.js
+++ b/browser/extensions/pdfjs/pdfjs.js
@@ -11,27 +11,21 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 "use strict";
 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "PdfStreamConverter",
   "resource://pdf.js/PdfStreamConverter.jsm");
 
 // Register/unregister a constructor as a factory.
 function StreamConverterFactory() {
   if (Services.cpmm.sharedData.get("pdfjs.enabled")) {
     return new PdfStreamConverter();
   }
   throw Cr.NS_ERROR_FACTORY_NOT_REGISTERED;
 }
-StreamConverterFactory.prototype = {
-  // properties required for XPCOM registration:
-  classID: Components.ID("{d0c5195d-e798-49d4-b1d3-9324328b2291}"),
-  classDescription: "pdf.js Component",
-};
 
-var NSGetFactory = XPCOMUtils.generateNSGetFactory([StreamConverterFactory]);
+var EXPORTED_SYMBOLS = ["StreamConverterFactory"];
deleted file mode 100644
--- a/browser/extensions/pdfjs/pdfjs.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-component {d0c5195d-e798-49d4-b1d3-9324328b2291} pdfjs.js
-contract @mozilla.org/streamconv;1?from=application/pdf&to=*/* {d0c5195d-e798-49d4-b1d3-9324328b2291}
-contract @mozilla.org/streamconv;1?from=application/pdf&to=text/html {d0c5195d-e798-49d4-b1d3-9324328b2291}
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -155,235 +155,71 @@
 @BINPATH@/Accessible.tlb
 @BINPATH@/AccessibleHandler.dll
 @BINPATH@/AccessibleMarshal.dll
 @BINPATH@/IA2Marshal.dll
 #endif
 #endif
 
 ; JavaScript components
-@RESPATH@/components/ConsoleAPI.manifest
-@RESPATH@/components/ConsoleAPIStorage.js
-@RESPATH@/components/BrowserElementParent.manifest
-@RESPATH@/components/BrowserElementParent.js
-@RESPATH@/components/UAOverridesBootstrapper.js
-@RESPATH@/components/UAOverridesBootstrapper.manifest
-@RESPATH@/components/WellKnownOpportunisticUtils.js
-@RESPATH@/components/WellKnownOpportunisticUtils.manifest
-#ifndef XP_MACOSX
-; OSX uses native platform impl.  Windows, Linux, and Android uses fallback JS impl.
-@BINPATH@/components/nsDNSServiceDiscovery.manifest
-@BINPATH@/components/nsDNSServiceDiscovery.js
-#endif
 @RESPATH@/browser/components/BrowserComponents.manifest
-@RESPATH@/browser/components/nsBrowserContentHandler.js
-@RESPATH@/browser/components/nsBrowserGlue.js
-@RESPATH@/browser/components/devtools-startup.manifest
-@RESPATH@/browser/components/devtools-startup.js
-@RESPATH@/browser/components/aboutdebugging-registration.js
-@RESPATH@/browser/components/aboutdebugging.manifest
-#ifdef NIGHTLY_BUILD
-@RESPATH@/browser/components/aboutdebugging-new-registration.js
-@RESPATH@/browser/components/aboutdebugging-new.manifest
-#endif
-@RESPATH@/browser/components/aboutdevtools-registration.js
-@RESPATH@/browser/components/aboutdevtools.manifest
-@RESPATH@/browser/components/aboutdevtoolstoolbox-registration.js
-@RESPATH@/browser/components/aboutdevtoolstoolbox.manifest
-@RESPATH@/browser/components/aboutNewTabService.js
-@RESPATH@/browser/components/NewTabComponents.manifest
 @RESPATH@/browser/components/EnterprisePolicies.js
 @RESPATH@/browser/components/EnterprisePoliciesContent.js
 @RESPATH@/browser/components/EnterprisePolicies.manifest
-@RESPATH@/browser/components/WebProtocolHandlerRegistrar.js
-@RESPATH@/components/Downloads.manifest
-@RESPATH@/components/DownloadLegacy.js
-@RESPATH@/components/PageThumbsComponents.manifest
-@RESPATH@/components/crashmonitor.manifest
-@RESPATH@/components/nsCrashMonitor.js
 @RESPATH@/components/toolkitsearch.manifest
-@RESPATH@/components/nsSearchService.js
-@RESPATH@/components/nsSearchSuggestions.js
-@RESPATH@/components/nsSidebar.js
-#ifdef NIGHTLY_BUILD
-@RESPATH@/browser/components/payments.manifest
-@RESPATH@/browser/components/paymentUIService.js
-#endif
-@RESPATH@/components/passwordmgr.manifest
-@RESPATH@/components/nsLoginInfo.js
-@RESPATH@/components/nsLoginManager.js
-@RESPATH@/components/nsLoginManagerPrompter.js
-@RESPATH@/components/storage-json.js
-@RESPATH@/components/crypto-SDR.js
-@RESPATH@/components/TooltipTextProvider.js
-@RESPATH@/components/TooltipTextProvider.manifest
 @RESPATH@/components/WebVTT.manifest
 @RESPATH@/components/WebVTTParserWrapper.js
-@RESPATH@/components/nsHelperAppDlg.manifest
-@RESPATH@/components/nsHelperAppDlg.js
-@RESPATH@/components/NetworkGeolocationProvider.manifest
-@RESPATH@/components/NetworkGeolocationProvider.js
 @RESPATH@/components/extensions.manifest
-@RESPATH@/components/addonManager.js
-@RESPATH@/components/amContentHandler.js
-@RESPATH@/components/amInstallTrigger.js
-@RESPATH@/components/amWebAPI.js
 #ifdef MOZ_UPDATER
 @RESPATH@/components/nsUpdateService.manifest
-@RESPATH@/components/nsUpdateService.js
-@RESPATH@/components/nsUpdateServiceStub.js
 #endif
-@RESPATH@/components/nsUpdateTimerManager.manifest
-@RESPATH@/components/nsUpdateTimerManager.js
-@RESPATH@/components/utils.manifest
-@RESPATH@/components/simpleServices.js
 @RESPATH@/components/ProcessSingleton.manifest
-@RESPATH@/components/MainProcessSingleton.js
-@RESPATH@/components/ContentProcessSingleton.js
-@RESPATH@/components/nsURLFormatter.manifest
-@RESPATH@/components/nsURLFormatter.js
-@RESPATH@/components/toolkitplaces.manifest
-@RESPATH@/components/nsTaggingService.js
-@RESPATH@/components/UnifiedComplete.js
-@RESPATH@/components/nsPlacesExpiration.js
-@RESPATH@/components/PageIconProtocolHandler.js
-@RESPATH@/components/PlacesCategoriesStarter.js
-@RESPATH@/components/ColorAnalyzer.js
-@RESPATH@/components/PageThumbsStorageService.js
-@RESPATH@/components/mozProtocolHandler.js
-@RESPATH@/components/mozProtocolHandler.manifest
-@RESPATH@/components/nsDefaultCLH.manifest
-@RESPATH@/components/nsDefaultCLH.js
-@RESPATH@/components/ContentPrefService2.manifest
-@RESPATH@/components/ContentPrefService2.js
-@RESPATH@/components/nsContentDispatchChooser.manifest
-@RESPATH@/components/nsContentDispatchChooser.js
 @RESPATH@/components/HandlerService.manifest
 @RESPATH@/components/HandlerService.js
-@RESPATH@/components/nsWebHandlerApp.manifest
-@RESPATH@/components/nsWebHandlerApp.js
-@RESPATH@/components/satchel.manifest
-@RESPATH@/components/nsFormAutoComplete.js
-@RESPATH@/components/FormHistoryStartup.js
-@RESPATH@/components/nsInputListAutoComplete.js
-@RESPATH@/components/contentAreaDropListener.manifest
-@RESPATH@/components/contentAreaDropListener.js
-@RESPATH@/browser/components/BrowserProfileMigrators.manifest
-@RESPATH@/browser/components/ProfileMigrator.js
-@RESPATH@/browser/components/ChromeProfileMigrator.js
-@RESPATH@/browser/components/FirefoxProfileMigrator.js
-#ifdef XP_WIN
-@RESPATH@/browser/components/360seProfileMigrator.js
-@RESPATH@/browser/components/EdgeProfileMigrator.js
-@RESPATH@/browser/components/IEProfileMigrator.js
-#endif
 #ifdef XP_MACOSX
-@RESPATH@/browser/components/SafariProfileMigrator.js
 @RESPATH@/browser/components/MacTouchBar.manifest
 @RESPATH@/browser/components/MacTouchBar.js
 #endif
-@RESPATH@/components/nsPrompter.manifest
-@RESPATH@/components/nsPrompter.js
 @RESPATH@/components/SyncComponents.manifest
-@RESPATH@/components/Weave.js
-@RESPATH@/components/FxAccountsComponents.manifest
-@RESPATH@/components/FxAccountsPush.js
-@RESPATH@/components/CaptivePortalDetectComponents.manifest
-@RESPATH@/components/captivedetect.js
 @RESPATH@/components/servicesComponents.manifest
 @RESPATH@/components/servicesSettings.manifest
-@RESPATH@/components/RemoteSettingsComponents.js
 @RESPATH@/components/cryptoComponents.manifest
-@RESPATH@/components/TelemetryStartup.js
-@RESPATH@/components/TelemetryStartup.manifest
-@RESPATH@/components/XULStore.js
-@RESPATH@/components/XULStore.manifest
-@RESPATH@/components/recording-cmdline.js
-@RESPATH@/components/recording-cmdline.manifest
-@RESPATH@/components/htmlMenuBuilder.js
-@RESPATH@/components/htmlMenuBuilder.manifest
-
-@RESPATH@/components/NotificationStorage.js
-@RESPATH@/components/NotificationStorage.manifest
-@RESPATH@/components/Push.js
-@RESPATH@/components/Push.manifest
-@RESPATH@/components/PushComponents.js
 
-@RESPATH@/components/remotebrowserutils.manifest
-@RESPATH@/components/RemoteWebNavigation.js
-
-@RESPATH@/components/ProcessSelector.js
-@RESPATH@/components/ProcessSelector.manifest
-
-@RESPATH@/components/SlowScriptDebug.manifest
-@RESPATH@/components/SlowScriptDebug.js
-
-@RESPATH@/components/ClearDataService.manifest
-@RESPATH@/components/ClearDataService.js
-
-#ifdef MOZ_WEBRTC
-@RESPATH@/components/PeerConnection.js
-@RESPATH@/components/PeerConnection.manifest
-#endif
+@RESPATH@/components/Push.manifest
 
 ; Remote control protocol
 #ifdef ENABLE_MARIONETTE
 @RESPATH@/chrome/marionette@JAREXT@
 @RESPATH@/chrome/marionette.manifest
 @RESPATH@/components/marionette.manifest
 @RESPATH@/components/marionette.js
 @RESPATH@/defaults/pref/marionette.js
 #endif
 
-@RESPATH@/components/nsAsyncShutdown.manifest
-@RESPATH@/components/nsAsyncShutdown.js
-
-@RESPATH@/components/BuiltinProviders.manifest
-@RESPATH@/components/PresentationControlService.js
-@RESPATH@/components/PresentationDataChannelSessionTransport.js
-@RESPATH@/components/PresentationDataChannelSessionTransport.manifest
-
-@RESPATH@/components/mozIntl.manifest
-@RESPATH@/components/mozIntl.js
-
 #if defined(ENABLE_TESTS) && defined(MOZ_DEBUG)
 @RESPATH@/components/TestInterfaceJS.js
 @RESPATH@/components/TestInterfaceJS.manifest
 @RESPATH@/components/TestInterfaceJSMaplike.js
 #endif
 
 #if defined(MOZ_DEBUG) || defined(MOZ_DEV_EDITION) || defined(NIGHTLY_BUILD)
 @RESPATH@/browser/components/testComponents.manifest
 @RESPATH@/browser/components/startupRecorder.js
 #endif
 
 ; [Extensions]
 @RESPATH@/components/extensions-toolkit.manifest
 @RESPATH@/browser/components/extensions-browser.manifest
 
-; [Normandy]
-@RESPATH@/components/shield.manifest
-@RESPATH@/components/shield-content-process.js
-
-; [PDF Viewer]
-@RESPATH@/browser/components/pdfjs.manifest
-@RESPATH@/browser/components/pdfjs.js
-
 ; Modules
 @RESPATH@/browser/modules/*
 @RESPATH@/modules/*
 @RESPATH@/browser/actors/*
 @RESPATH@/actors/*
 
-; Safe Browsing
-@RESPATH@/components/nsURLClassifier.manifest
-@RESPATH@/components/nsUrlClassifierHashCompleter.js
-@RESPATH@/components/nsUrlClassifierListManager.js
-@RESPATH@/components/nsUrlClassifierLib.js
-
 ; Security Reports
 @RESPATH@/components/SecurityReporter.manifest
 @RESPATH@/components/SecurityReporter.js
 
 ; ANGLE GLES-on-D3D rendering library
 #ifdef MOZ_ANGLE_RENDERER
 @BINPATH@/libEGL.dll
 @BINPATH@/libGLESv2.dll
@@ -559,18 +395,16 @@ bin/libfreebl_32int64_3.so
 #ifdef MOZ_MAINTENANCE_SERVICE
 @BINPATH@/maintenanceservice.exe
 @BINPATH@/maintenanceservice_installer.exe
 #endif
 
 ; [Crash Reporter]
 ;
 #ifdef MOZ_CRASHREPORTER
-@RESPATH@/components/CrashService.manifest
-@RESPATH@/components/CrashService.js
 #ifdef XP_MACOSX
 @BINPATH@/crashreporter.app/
 #else
 @BINPATH@/crashreporter@BIN_SUFFIX@
 @RESPATH@/crashreporter.ini
 @BINPATH@/minidump-analyzer@BIN_SUFFIX@
 #ifdef XP_UNIX
 @RESPATH@/Throbber-small.gif
@@ -582,17 +416,16 @@ bin/libfreebl_32int64_3.so
 #endif
 #endif
 
 ; [ Ping Sender ]
 ;
 @BINPATH@/pingsender@BIN_SUFFIX@
 
 ; Shutdown Terminator
-@RESPATH@/components/nsTerminatorTelemetry.js
 @RESPATH@/components/terminator.manifest
 
 #ifdef LLVM_SYMBOLIZER
 @BINPATH@/@LLVM_SYMBOLIZER@
 ; On Windows, llvm-symbolizer depends on the MS DIA library.
 #ifdef WIN_DIA_SDK_BIN_DIR
 @BINPATH@/msdia140.dll
 #endif
@@ -602,36 +435,23 @@ bin/libfreebl_32int64_3.so
 @BINPATH@/@MOZ_CLANG_RT_ASAN_LIB@
 #endif
 
 
 ; media
 @RESPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
 @RESPATH@/gmp-clearkey/0.1/manifest.json
 
-; gfx
-#ifdef XP_WIN
-@RESPATH@/components/GfxSanityTest.manifest
-@RESPATH@/components/SanityTest.js
-#endif
-
 #ifdef MOZ_DMD
 ; DMD
 @RESPATH@/dmd.py
 @RESPATH@/fix_stack_using_bpsyms.py
 #ifdef XP_MACOSX
 @RESPATH@/fix_macosx_stack.py
 #endif
 #ifdef XP_LINUX
 @RESPATH@/fix_linux_stack.py
 #endif
 #endif
 
-; NOTE: This must match the config checks in
-; /toolkit/components/backgroundhangmonitor/moz.build.
-#if defined(NIGHTLY_BUILD) && !defined(MOZ_DEBUG) && !defined(MOZ_TSAN) && !defined(MOZ_ASAN)
-@RESPATH@/components/BHRTelemetryService.js
-@RESPATH@/components/BHRTelemetryService.manifest
-#endif
-
 #ifdef PKG_LOCALE_MANIFEST
 #include @PKG_LOCALE_MANIFEST@
 #endif
--- a/browser/installer/windows/nsis/installer.nsi
+++ b/browser/installer/windows/nsis/installer.nsi
@@ -479,29 +479,16 @@ Section "-Application" APP_IDX
   ${WriteRegStr2} $TmpVal "$0" "" "$INSTDIR\${FileMainEXE}" 0
   ${WriteRegStr2} $TmpVal "$0" "Path" "$INSTDIR" 0
 
   StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\$R9"
   ${CreateRegKey} "$TmpVal" "$0" 0
   StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\plugin-container.exe"
   ${CreateRegKey} "$TmpVal" "$0" 0
 
-  ; MaxLoaderThreads option is only required on AArch64 (ARM64) and it can only
-  ; be set in HKEY_LOCAL_MACHINE.
-  ${If} "${ARCH}" == "AArch64"
-  ${AndIf} $TmpVal == "HKLM"
-    StrCpy $0 "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\${FileMainEXE}"
-    ${CreateRegKey} "$TmpVal" "$0" 0
-    ${WriteRegDWORD2} $TmpVal "$0" "MaxLoaderThreads" 1 0
-
-    StrCpy $0 "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\plugin-container.exe"
-    ${CreateRegKey} "$TmpVal" "$0" 0
-    ${WriteRegDWORD2} $TmpVal "$0" "MaxLoaderThreads" 1 0
-  ${EndIf}
-
   ${If} $TmpVal == "HKLM"
     ; Set the permitted LSP Categories
     ${SetAppLSPCategories} ${LSP_CATEGORIES}
   ${EndIf}
 
 !ifdef MOZ_LAUNCHER_PROCESS
 !ifdef RELEASE_OR_BETA
   ${DisableLauncherProcessByDefault}
--- a/browser/installer/windows/nsis/shared.nsh
+++ b/browser/installer/windows/nsis/shared.nsh
@@ -53,16 +53,27 @@
 
     ; Add the Firewall entries after an update
     Call AddFirewallEntries
 
     ReadRegStr $0 HKLM "Software\mozilla.org\Mozilla" "CurrentVersion"
     ${If} "$0" != "${GREVersion}"
       WriteRegStr HKLM "Software\mozilla.org\Mozilla" "CurrentVersion" "${GREVersion}"
     ${EndIf}
+
+    ; Image File Execution Options were set for a short period on AArch64 (ARM64)
+    ; to disable multi-threaded DLL loading, which breaks with the sandbox.
+    ; A better solution was found, so this code is to clean up any entries left
+    ; lying around. Bug 1525981 tracks removing this.
+    ${If} "${ARCH}" == "AArch64"
+      StrCpy $0 "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\${FileMainEXE}"
+      DeleteRegKey HKLM "$0"
+      StrCpy $0 "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\plugin-container.exe"
+      DeleteRegKey HKLM "$0"
+    ${EndIf}
   ${EndIf}
 
   ; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details).
   ${MigrateTaskBarShortcut}
 
   ; Update the name/icon/AppModelID of our shortcuts as needed, then update the
   ; lastwritetime of the Start Menu shortcut to clear the tile icon cache.
   ; Do this for both shell contexts in case the user has shortcuts in multiple
--- a/browser/installer/windows/nsis/uninstaller.nsi
+++ b/browser/installer/windows/nsis/uninstaller.nsi
@@ -368,23 +368,16 @@ Section "Uninstall"
     DeleteRegKey HKLM "$0"
     DeleteRegKey HKCU "$0"
     StrCpy $0 "Software\Microsoft\MediaPlayer\ShimInclusionList\plugin-container.exe"
     DeleteRegKey HKLM "$0"
     DeleteRegKey HKCU "$0"
     StrCpy $0 "Software\Classes\MIME\Database\Content Type\application/x-xpinstall;app=firefox"
     DeleteRegKey HKLM "$0"
     DeleteRegKey HKCU "$0"
-    ; Image File Execution Options are only set on AArch64 (ARM64).
-    ${If} "${ARCH}" == "AArch64"
-      StrCpy $0 "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\${FileMainEXE}"
-      DeleteRegKey HKLM "$0"
-      StrCpy $0 "Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\plugin-container.exe"
-      DeleteRegKey HKLM "$0"
-    ${EndIf}
   ${Else}
     ReadRegStr $R1 HKLM "$0" ""
     ${un.RemoveQuotesFromPath} "$R1" $R1
     ${un.GetParent} "$R1" $R1
     ${If} "$INSTDIR" == "$R1"
       WriteRegStr HKLM "$0" "" "$R9"
       ${un.GetParent} "$R9" $R1
       WriteRegStr HKLM "$0" "Path" "$R1"
--- a/browser/modules/ContentClick.jsm
+++ b/browser/modules/ContentClick.jsm
@@ -10,17 +10,17 @@ var EXPORTED_SYMBOLS = [ "ContentClick" 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "PlacesUIUtils",
                                "resource:///modules/PlacesUIUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
                                "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 var ContentClick = {
-  // Listeners are added in nsBrowserGlue.js
+  // Listeners are added in BrowserGlue.jsm
   receiveMessage(message) {
     switch (message.name) {
       case "Content:Click":
         this.contentAreaClick(message.json, message.target);
         break;
     }
   },
 
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -148,17 +148,17 @@ var ContentSearch = {
    *         The MessageManager object of the selected browser.
    */
   focusInput(messageManager) {
     messageManager.sendAsyncMessage(OUTBOUND_MESSAGE, {
       type: "FocusInput",
     });
   },
 
-  // Listeners and observers are added in nsBrowserGlue.js
+  // Listeners and observers are added in BrowserGlue.jsm
   receiveMessage(msg) {
     // Add a temporary event handler that exists only while the message is in
     // the event queue.  If the message's source docshell changes browsers in
     // the meantime, then we need to update msg.target.  event.detail will be
     // the docshell's new parent <xul:browser> element.
     msg.handleEvent = event => {
       let browserData = this._suggestionMap.get(msg.target);
       if (browserData) {
--- a/browser/modules/FormValidationHandler.jsm
+++ b/browser/modules/FormValidationHandler.jsm
@@ -27,17 +27,17 @@ var FormValidationHandler =
   hidePopup() {
     this._hidePopup();
   },
 
   /*
    * Events
    */
 
-  // Listeners are added in nsBrowserGlue.js
+  // Listeners are added in BrowserGlue.jsm
   receiveMessage(aMessage) {
     let window = aMessage.target.ownerGlobal;
     let json = aMessage.json;
     let tabBrowser = window.gBrowser;
     switch (aMessage.name) {
       case "FormValidation:ShowPopup":
         // target is the <browser>, make sure we're receiving a message
         // from the foreground tab.
--- a/browser/modules/HomePage.jsm
+++ b/browser/modules/HomePage.jsm
@@ -5,18 +5,16 @@
 /* globals ChromeUtils, Services */
 /* exported HomePage */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["HomePage"];
 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
-                               "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 const kPrefName = "browser.startup.homepage";
 
 function getHomepagePref(useDefault) {
   let homePage;
   let prefs = Services.prefs;
   if (useDefault) {
     prefs = prefs.getDefaultBranch(null);
@@ -40,46 +38,24 @@ function getHomepagePref(useDefault) {
     Services.prefs.clearUserPref(kPrefName);
     homePage = getHomepagePref(true);
   }
 
   return homePage;
 }
 
 let HomePage = {
-  get(aWindow) {
-    if (PrivateBrowsingUtils.permanentPrivateBrowsing ||
-        (aWindow && PrivateBrowsingUtils.isWindowPrivate(aWindow))) {
-      return this.getPrivate();
-    }
+  get() {
     return getHomepagePref();
   },
 
   getDefault() {
     return getHomepagePref(true);
   },
 
-  getPrivate() {
-    let homePages = getHomepagePref();
-    if (!homePages.includes("moz-extension")) {
-      return homePages;
-    }
-    // Verify private access and build a new list.
-    let privateHomePages = homePages.split("|").filter(page => {
-      let url = new URL(page);
-      if (url.protocol !== "moz-extension:") {
-        return true;
-      }
-      let policy = WebExtensionPolicy.getByHostname(url.hostname);
-      return policy && policy.privateBrowsingAllowed;
-    });
-    // Extensions may not be ready on startup, fallback to defaults.
-    return privateHomePages.join("|") || this.getDefault();
-  },
-
   get overridden() {
     return Services.prefs.prefHasUserValue(kPrefName);
   },
 
   set(value) {
     Services.prefs.setStringPref(kPrefName, value);
   },
 
--- a/browser/modules/ProcessHangMonitor.jsm
+++ b/browser/modules/ProcessHangMonitor.jsm
@@ -453,18 +453,17 @@ var ProcessHangMonitor = {
       let addonName = aps.getExtensionName(report.addonId);
 
       let label = bundle.getFormattedString("processHang.add-on.label",
                                             [addonName, brandBundle.getString("brandShortName")]);
 
       let linkText = bundle.getString("processHang.add-on.learn-more.text");
       let linkURL = "https://support.mozilla.org/kb/warning-unresponsive-script#w_other-causes";
 
-      let link = doc.createXULElement("label");
-      link.setAttribute("class", "text-link");
+      let link = doc.createXULElement("label", {is: "text-link"});
       link.setAttribute("role", "link");
       link.setAttribute("onclick", `openTrustedLinkIn(${JSON.stringify(linkURL)}, "tab")`);
       link.setAttribute("value", linkText);
 
       message = doc.createDocumentFragment();
       message.appendChild(doc.createTextNode(label + " "));
       message.appendChild(link);
 
--- a/browser/modules/ReaderParent.jsm
+++ b/browser/modules/ReaderParent.jsm
@@ -10,17 +10,17 @@ var EXPORTED_SYMBOLS = [ "ReaderParent" 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm");
 
 const gStringBundle = Services.strings.createBundle("chrome://global/locale/aboutReader.properties");
 
 var ReaderParent = {
-  // Listeners are added in nsBrowserGlue.js
+  // Listeners are added in BrowserGlue.jsm
   receiveMessage(message) {
     switch (message.name) {
       case "Reader:FaviconRequest": {
         if (message.target.messageManager) {
           try {
             let preferredWidth = message.data.preferredWidth || 0;
             let uri = Services.io.newURI(message.data.url);
             PlacesUtils.favicons.getFaviconURLForPage(uri, iconUri => {
--- a/browser/modules/RemotePrompt.jsm
+++ b/browser/modules/RemotePrompt.jsm
@@ -8,17 +8,17 @@
 var EXPORTED_SYMBOLS = [ "RemotePrompt" ];
 
 ChromeUtils.defineModuleGetter(this, "PromptUtils",
                                "resource://gre/modules/SharedPromptUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "Services",
                                "resource://gre/modules/Services.jsm");
 
 var RemotePrompt = {
-  // Listeners are added in nsBrowserGlue.js
+  // Listeners are added in BrowserGlue.jsm
   receiveMessage(message) {
     switch (message.name) {
       case "Prompt:Open":
         if (message.data.uri) {
           this.openModalWindow(message.data, message.target);
         } else {
           this.openTabPrompt(message.data, message.target);
         }
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -196,17 +196,17 @@ var webrtcUI = {
   on(...args) {
     return this.emitter.on(...args);
   },
 
   off(...args) {
     return this.emitter.off(...args);
   },
 
-  // Listeners and observers are registered in nsBrowserGlue.js
+  // Listeners and observers are registered in BrowserGlue.jsm
   receiveMessage(aMessage) {
     switch (aMessage.name) {
       case "rtcpeer:Request": {
         let params = Object.freeze(Object.assign({
           origin: aMessage.target.contentPrincipal.origin,
         }, aMessage.data));
 
         let blockers = Array.from(this.peerConnectionBlockers);
@@ -714,18 +714,17 @@ function prompt(aBrowser, aRequest) {
             let string;
             let bundle = chromeWin.gNavigatorBundle;
 
             let learnMoreText =
               bundle.getString("getUserMedia.shareScreen.learnMoreLabel");
             let baseURL =
               Services.urlFormatter.formatURLPref("app.support.baseURL");
 
-            let learnMore = chromeWin.document.createXULElement("label");
-            learnMore.className = "text-link";
+            let learnMore = chromeWin.document.createXULElement("label", {is: "text-link"});
             learnMore.setAttribute("href", baseURL + "screenshare-safety");
             learnMore.textContent = learnMoreText;
 
             if (type == "screen") {
               string = bundle.getFormattedString("getUserMedia.shareScreenWarning.message",
                                                  ["<>"]);
             } else {
               let brand =
--- a/browser/themes/shared/compacttheme.inc.css
+++ b/browser/themes/shared/compacttheme.inc.css
@@ -9,13 +9,13 @@
 :root:-moz-lwtheme {
   --toolbar-non-lwt-bgcolor: var(--toolbar-bgcolor);
   --toolbar-non-lwt-textcolor: var(--lwt-text-color);
   --toolbar-non-lwt-bgimage: none;
 }
 
 :root:-moz-lwtheme-brighttext {
   /* !important to override LightweightThemeManager.addBuiltInTheme in
-     nsBrowserGlue.js */
+     BrowserGlue.jsm */
   --autocomplete-popup-background: #2A2A2E !important;
   --autocomplete-popup-highlight-background: #0060DF;
 }
 
--- a/build/docs/defining-xpcom-components.rst
+++ b/build/docs/defining-xpcom-components.rst
@@ -97,16 +97,22 @@ Class definitions may have the following
   The fully-qualified name of a constructor function to call in order to
   create instances of this class. This function must be declared in one of the
   headers listed in the ``headers`` property, must take no arguments, and must
   return ``already_AddRefed<iface>`` where ``iface`` is the interface provided
   in the ``type`` property.
   
   This property is incompatible with ``legacy_constructor``.
 
+``jsm`` (optional)
+  If provided, must be the URL of a JavaScript module which contains a
+  JavaScript implementation of the component. The ``constructor`` property
+  must contain the name of an exported function which can be constructed to
+  create a new instance of the component.
+
 ``legacy_constructor`` (optional)
   This property is deprecated, and should not be used in new code.
   
   The fully-qualified name of a constructor function to call in order to
   create instances of this class. This function must be declared in one of the
   headers listed in the ``headers`` property, and must have the signature
   ``nsresult(nsISupports* aOuter, const nsID& aIID, void** aResult)``, and
   behave equivalently to ``nsIFactory::CreateInstance``.
--- a/build/mozconfig.no-compile
+++ b/build/mozconfig.no-compile
@@ -30,8 +30,9 @@ unset VC_PATH
 unset WINDOWSSDKDIR
 
 unset MOZ_STDCXX_COMPAT
 unset MOZ_NO_PIE_COMPAT
 
 unset AR
 unset NM
 unset RANLIB
+unset NASM
--- a/chrome/test/unit/test_data_protocol_registration.js
+++ b/chrome/test/unit/test_data_protocol_registration.js
@@ -50,17 +50,16 @@ function run_test() {
       // to be restored later and register the new one.
       if (registrar.isContractIDRegistered(factory.contractID)) {
         dump(factory.scheme + " is already registered. Storing currently registered object for restoration later.");
         old_factories.push({
           CID: registrar.contractIDToCID(factory.contractID),
           factory: Components.manager.getClassObject(Cc[factory.contractID], Ci.nsIFactory),
         });
         old_factories_inds.push(true);
-        registrar.unregisterFactory(old_factories[i].CID, old_factories[i].factory);
       } else {
         dump(factory.scheme + " has never been registered. Registering...");
         old_factories.push({CID: "", factory: null});
         old_factories_inds.push(false);
       }
 
       registrar.registerFactory(factory.CID, "test-" + factory.scheme, factory.contractID, factory);
     } else {
@@ -90,12 +89,12 @@ function run_test() {
   // Unregister our factories so we do not leak
   for (let i = 0; i < factories.length; i++) {
     let factory = factories[i];
     let ind = old_factories_inds[i];
     registrar.unregisterFactory(factory.CID, factory);
 
     if (ind) {
       let old_factory = old_factories[i];
-      registrar.registerFactory(old_factory.CID, factory.scheme, factory.contractID, old_factory.factory);
+      registrar.registerFactory(old_factory.CID, factory.scheme, factory.contractID, null);
     }
   }
 }
--- a/chrome/test/unit/test_no_remote_registration.js
+++ b/chrome/test/unit/test_no_remote_registration.js
@@ -120,17 +120,16 @@ function run_test() {
   if (!registrar.isCIDRegistered(XULAppInfoFactory.CID)) {
     // Check to see if a contract was already registered and
     // register it if it is not. Otherwise, store the previous one
     // to be restored later and register the new one.
     if (registrar.isContractIDRegistered(XULAppInfoFactory.contractID)) {
       dump(XULAppInfoFactory.scheme + " is already registered. Storing currently registered object for restoration later.");
       old_factory.CID = registrar.contractIDToCID(XULAppInfoFactory.contractID);
       old_factory.factory = Components.manager.getClassObject(Cc[XULAppInfoFactory.contractID], Ci.nsIFactory);
-      registrar.unregisterFactory(old_factory.CID, old_factory.factory);
     } else {
       dump(XULAppInfoFactory.scheme + " has never been registered. Registering...");
     }
 
     registrar.registerFactory(XULAppInfoFactory.CID, "test-" + XULAppInfoFactory.scheme, XULAppInfoFactory.contractID, XULAppInfoFactory);
   } else {
     do_throw("CID " + XULAppInfoFactory.CID + " has already been registered!");
   }
@@ -209,11 +208,11 @@ function run_test() {
   for (let i = 0; i < factories.length; i++) {
     let factory = factories[i];
     registrar.unregisterFactory(factory.CID, factory);
   }
 
   // Unregister XULAppInfoFactory
   registrar.unregisterFactory(XULAppInfoFactory.CID, XULAppInfoFactory);
   if (old_factory.factory != null) {
-    registrar.registerFactory(old_factory.CID, "", XULAppInfoFactory.contractID, old_factory.factory);
+    registrar.registerFactory(old_factory.CID, "", XULAppInfoFactory.contractID, null);
   }
 }
rename from devtools/startup/aboutdebugging-new-registration.js
rename to devtools/startup/AboutDebuggingNewRegistration.jsm
--- a/devtools/startup/aboutdebugging-new-registration.js
+++ b/devtools/startup/AboutDebuggingNewRegistration.jsm
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // This component is only registered and packaged for local and nightly builds in order to
 // open the new about:debugging when going to about:debugging-new, without having to flip
 // the preference. This allows running both versions of about:debugging side by side to
 // compare them.
-const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const { nsIAboutModule } = Ci;
 
 function AboutDebuggingNew() {}
 
 AboutDebuggingNew.prototype = {
   classDescription: "about:debugging-new",
@@ -33,11 +32,9 @@ AboutDebuggingNew.prototype = {
     return chan;
   },
 
   getURIFlags: function(uri) {
     return nsIAboutModule.ALLOW_SCRIPT;
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
-  AboutDebuggingNew,
-]);
+var EXPORTED_SYMBOLS = ["AboutDebuggingNew"];
rename from devtools/startup/aboutdebugging-registration.js
rename to devtools/startup/AboutDebuggingRegistration.jsm
--- a/devtools/startup/aboutdebugging-registration.js
+++ b/devtools/startup/AboutDebuggingRegistration.jsm
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Register the about:debugging URL, that allows to debug various targets such as addons,
 // workers and tabs by launching a dedicated DevTools toolbox for the selected target.
 // If DevTools are not installed, this about page will display a shim landing page
 // encouraging the user to download and install DevTools.
-const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const { nsIAboutModule } = Ci;
 
 function AboutDebugging() {}
 
 AboutDebugging.prototype = {
   classDescription: "about:debugging",
@@ -35,11 +34,9 @@ AboutDebugging.prototype = {
     return chan;
   },
 
   getURIFlags: function(uri) {
     return nsIAboutModule.ALLOW_SCRIPT;
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
-  AboutDebugging,
-]);
+var EXPORTED_SYMBOLS = ["AboutDebugging"];
rename from devtools/startup/aboutdevtoolstoolbox-registration.js
rename to devtools/startup/AboutDevToolsToolboxRegistration.jsm
--- a/devtools/startup/aboutdevtoolstoolbox-registration.js
+++ b/devtools/startup/AboutDevToolsToolboxRegistration.jsm
@@ -2,17 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Register about:devtools-toolbox which allows to open a devtools toolbox
 // in a Firefox tab or a custom html iframe in browser.html
 
-const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const { nsIAboutModule } = Ci;
 
 function AboutDevtoolsToolbox() {}
 
 AboutDevtoolsToolbox.prototype = {
   uri: Services.io.newURI("chrome://devtools/content/framework/toolbox.xul"),
@@ -30,11 +29,9 @@ AboutDevtoolsToolbox.prototype = {
 
   getURIFlags: function(uri) {
     return nsIAboutModule.ALLOW_SCRIPT |
            nsIAboutModule.ENABLE_INDEXED_DB |
            nsIAboutModule.HIDE_FROM_ABOUTABOUT;
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
-  AboutDevtoolsToolbox,
-]);
+var EXPORTED_SYMBOLS = ["AboutDevtoolsToolbox"];
rename from devtools/startup/devtools-startup.js
rename to devtools/startup/DevToolsStartup.jsm
--- a/devtools/startup/devtools-startup.js
+++ b/devtools/startup/DevToolsStartup.jsm
@@ -1002,10 +1002,9 @@ const JsonView = {
         onError(status) {
           throw new Error("JSON Viewer's onSave failed in startPersistence");
         },
       });
     }
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
-  [DevToolsStartup]);
+var EXPORTED_SYMBOLS = ["DevToolsStartup"];
deleted file mode 100644
--- a/devtools/startup/aboutdebugging-new.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {610e4e26-26bd-4a7d-aebc-69211d5a3be0} aboutdebugging-new-registration.js
-contract @mozilla.org/network/protocol/about;1?what=debugging-new {610e4e26-26bd-4a7d-aebc-69211d5a3be0}
deleted file mode 100644
--- a/devtools/startup/aboutdebugging.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {1060afaf-dc9e-43da-8646-23a2faf48493} aboutdebugging-registration.js
-contract @mozilla.org/network/protocol/about;1?what=debugging {1060afaf-dc9e-43da-8646-23a2faf48493}
\ No newline at end of file
rename from devtools/startup/aboutdevtools/aboutdevtools-registration.js
rename to devtools/startup/aboutdevtools/AboutDevToolsRegistration.jsm
--- a/devtools/startup/aboutdevtools/aboutdevtools-registration.js
+++ b/devtools/startup/aboutdevtools/AboutDevToolsRegistration.jsm
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Register the about:devtools URL, that is opened whenever a user attempts to open
 // DevTools for the first time.
-const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const { nsIAboutModule } = Ci;
 
 function AboutDevtools() {}
 
 AboutDevtools.prototype = {
   uri: Services.io.newURI("chrome://devtools-startup/content/aboutdevtools/aboutdevtools.xhtml"),
@@ -30,11 +29,9 @@ AboutDevtools.prototype = {
     return chan;
   },
 
   getURIFlags: function(uri) {
     return nsIAboutModule.ALLOW_SCRIPT;
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
-  AboutDevtools,
-]);
+var EXPORTED_SYMBOLS = ["AboutDevtools"];
deleted file mode 100644
--- a/devtools/startup/aboutdevtools/aboutdevtools.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {3a16d383-92bd-4c24-ac10-0e2bd66883ab} aboutdevtools-registration.js
-contract @mozilla.org/network/protocol/about;1?what=devtools {3a16d383-92bd-4c24-ac10-0e2bd66883ab}
new file mode 100644
--- /dev/null
+++ b/devtools/startup/aboutdevtools/components.conf
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{3a16d383-92bd-4c24-ac10-0e2bd66883ab}',
+        'contract_ids': ['@mozilla.org/network/protocol/about;1?what=devtools'],
+        'jsm': 'resource:///modules/AboutDevToolsRegistration.jsm',
+        'constructor': 'AboutDevtools',
+    },
+]
--- a/devtools/startup/aboutdevtools/moz.build
+++ b/devtools/startup/aboutdevtools/moz.build
@@ -1,12 +1,15 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-EXTRA_COMPONENTS += [
-  'aboutdevtools-registration.js',
-  'aboutdevtools.manifest',
+EXTRA_JS_MODULES += [
+  'AboutDevToolsRegistration.jsm',
+]
+
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
deleted file mode 100644
--- a/devtools/startup/aboutdevtoolstoolbox.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {11342911-3135-45a8-8d71-737a2b0ad469} aboutdevtoolstoolbox-registration.js
-contract @mozilla.org/network/protocol/about;1?what=devtools-toolbox {11342911-3135-45a8-8d71-737a2b0ad469}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/startup/components.conf
@@ -0,0 +1,40 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = []
+
+if buildconfig.substs['MOZ_DEVTOOLS'] == 'all':
+    Classes += [
+        {
+            'cid': '{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}',
+            'contract_ids': ['@mozilla.org/devtools/startup-clh;1'],
+            'jsm': 'resource:///modules/DevToolsStartup.jsm',
+            'constructor': 'DevToolsStartup',
+            'categories': {'command-line-handler': 'm-devtools'},
+        },
+        {
+            'cid': '{1060afaf-dc9e-43da-8646-23a2faf48493}',
+            'contract_ids': ['@mozilla.org/network/protocol/about;1?what=debugging'],
+            'jsm': 'resource:///modules/AboutDebuggingRegistration.jsm',
+            'constructor': 'AboutDebugging',
+        },
+        {
+            'cid': '{11342911-3135-45a8-8d71-737a2b0ad469}',
+            'contract_ids': ['@mozilla.org/network/protocol/about;1?what=devtools-toolbox'],
+            'jsm': 'resource:///modules/AboutDevToolsToolboxRegistration.jsm',
+            'constructor': 'AboutDevtoolsToolbox',
+        },
+    ]
+
+if defined('NIGHTLY_BUILD'):
+    Classes += [
+        {
+            'cid': '{610e4e26-26bd-4a7d-aebc-69211d5a3be0}',
+            'contract_ids': ['@mozilla.org/network/protocol/about;1?what=debugging-new'],
+            'jsm': 'resource:///modules/AboutDebuggingNewRegistration.jsm',
+            'constructor': 'AboutDebuggingNew',
+        },
+    ]
deleted file mode 100644
--- a/devtools/startup/devtools-startup.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-component {9e9a9283-0ce9-4e4a-8f1c-ba129a032c32} devtools-startup.js
-contract @mozilla.org/devtools/startup-clh;1 {9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}
-category command-line-handler m-devtools @mozilla.org/devtools/startup-clh;1
--- a/devtools/startup/moz.build
+++ b/devtools/startup/moz.build
@@ -7,32 +7,32 @@
 JAR_MANIFESTS += ['jar.mn']
 
 DIRS += [
     'preferences',
 ]
 
 # Register the startup components only for 'all' builds.
 if CONFIG['MOZ_DEVTOOLS'] == 'all':
-    EXTRA_COMPONENTS += [
-        'aboutdebugging-registration.js',
-        'aboutdebugging.manifest',
-        'aboutdevtoolstoolbox-registration.js',
-        'aboutdevtoolstoolbox.manifest',
-        'devtools-startup.js',
-        'devtools-startup.manifest',
+    EXTRA_JS_MODULES += [
+        'AboutDebuggingRegistration.jsm',
+        'AboutDevToolsToolboxRegistration.jsm',
+        'DevToolsStartup.jsm',
     ]
 
     DIRS += [
       'aboutdevtools',
       'locales',
     ]
 
 if CONFIG['NIGHTLY_BUILD']:
     EXTRA_COMPONENTS += [
-        'aboutdebugging-new-registration.js',
-        'aboutdebugging-new.manifest',
+        'AboutDebuggingNewRegistration.jsm',
     ]
 
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
+
 XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
 
 if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
     BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9823,22 +9823,16 @@ nsresult nsDocShell::DoURILoad(nsDocShel
 
   // We have to do this in case our OriginAttributes are different from the
   // OriginAttributes of the parent document. Or in case there isn't a
   // parent document.
   bool isTopLevelDoc = mItemType == typeContent &&
                        (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
                         GetIsMozBrowser());
 
-  if (isTopLevelDoc && GetDocument() && GetDocument()->GetChannel()) {
-    nsCOMPtr<nsILoadInfo> oldLoadInfo =
-        GetDocument()->GetChannel()->GetLoadInfo();
-    loadInfo->SetOpenerPolicy(oldLoadInfo->GetOpenerPolicy());
-  }
-
   OriginAttributes attrs;
 
   // Inherit origin attributes from PrincipalToInherit if inheritAttrs is
   // true. Otherwise we just use the origin attributes from docshell.
   if (inheritAttrs) {
     MOZ_ASSERT(aLoadState->PrincipalToInherit(),
                "We should have PrincipalToInherit here.");
     attrs = aLoadState->PrincipalToInherit()->OriginAttributesRef();
@@ -12994,49 +12988,31 @@ nsDocShell::SetOriginAttributesBeforeLoa
   if (!attrs.Init(aCx, aOriginAttributes)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   return SetOriginAttributes(attrs);
 }
 
 NS_IMETHODIMP
-nsDocShell::ResumeRedirectedLoad(uint64_t aIdentifier, int32_t aHistoryIndex) {
+nsDocShell::ResumeRedirectedLoad(uint64_t aIdentifier) {
   RefPtr<nsDocShell> self = this;
   RefPtr<ChildProcessChannelListener> cpcl =
       ChildProcessChannelListener::GetSingleton();
 
   // Call into InternalLoad with the pending channel when it is received.
-  cpcl->RegisterCallback(
-      aIdentifier, [self, aHistoryIndex](nsIChildChannel* aChannel) {
-        RefPtr<nsDocShellLoadState> loadState;
-        nsresult rv = nsDocShellLoadState::CreateFromPendingChannel(
-            aChannel, getter_AddRefs(loadState));
-        if (NS_WARN_IF(NS_FAILED(rv))) {
-          return;
-        }
-
-        // If we're performing a history load, locate the correct history entry,
-        // and set the relevant bits on our loadState.
-        if (aHistoryIndex >= 0) {
-          nsCOMPtr<nsISHistory> legacySHistory =
-              self->mSessionHistory->LegacySHistory();
-
-          nsCOMPtr<nsISHEntry> entry;
-          rv = legacySHistory->GetEntryAtIndex(aHistoryIndex,
-                                               getter_AddRefs(entry));
-          if (NS_SUCCEEDED(rv)) {
-            legacySHistory->InternalSetRequestedIndex(aHistoryIndex);
-            loadState->SetLoadType(LOAD_HISTORY);
-            loadState->SetSHEntry(entry);
-          }
-        }
-
-        self->InternalLoad(loadState, nullptr, nullptr);
-      });
+  cpcl->RegisterCallback(aIdentifier, [self](nsIChildChannel* aChannel) {
+    RefPtr<nsDocShellLoadState> loadState;
+    nsresult rv = nsDocShellLoadState::CreateFromPendingChannel(
+        aChannel, getter_AddRefs(loadState));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+    self->InternalLoad(loadState, nullptr, nullptr);
+  });
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetOriginAttributes(JS::Handle<JS::Value> aOriginAttributes,
                                 JSContext* aCx) {
   OriginAttributes attrs;
   if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
--- a/docshell/base/nsIWebNavigation.idl
+++ b/docshell/base/nsIWebNavigation.idl
@@ -337,15 +337,11 @@ interface nsIWebNavigation : nsISupports
    * Set an OriginAttributes dictionary in the docShell. This can be done only
    * before loading any content.
    */
   [implicit_jscontext]
   void setOriginAttributesBeforeLoading(in jsval originAttributes);
 
   /**
    * Resume a load which has been redirected from another process.
-   *
-   * A negative |aHistoryIndex| value corresponds to a non-history load being
-   * resumed.
    */
-  void resumeRedirectedLoad(in unsigned long long aLoadIdentifier,
-                            in long aHistoryIndex);
+  void resumeRedirectedLoad(in unsigned long long aLoadIdentifier);
 };
--- a/docshell/shistory/nsISHistory.idl
+++ b/docshell/shistory/nsISHistory.idl
@@ -48,24 +48,16 @@ interface nsISHistory: nsISupports
    * A readonly property of the interface that returns
    * the index of the last document that started to load and
    * didn't finished yet. When document finishes the loading
    * value -1 is returned.
    */
   [infallible] readonly attribute long requestedIndex;
 
   /**
-   * Artifically set the |requestedIndex| for this nsISHEntry to the given
-   * index. This is used when resuming a cross-process load from a different
-   * process.
-   */
-  [noscript, notxpcom]
-  void internalSetRequestedIndex(in long aRequestedIndex);
-
-  /**
    * Get the history entry at a given index. Returns non-null on success.
    *
    * @param index             The index value whose entry is requested.
    *                          The oldest entry is located at index == 0.
    * @return                  The found entry; never null.
    */
   nsISHEntry getEntryAtIndex(in long aIndex);
 
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -621,22 +621,16 @@ nsSHistory::SetIndex(int32_t aIndex) {
 /* Get the requestedIndex */
 NS_IMETHODIMP
 nsSHistory::GetRequestedIndex(int32_t* aResult) {
   MOZ_ASSERT(aResult, "null out param?");
   *aResult = mRequestedIndex;
   return NS_OK;
 }
 
-NS_IMETHODIMP_(void)
-nsSHistory::InternalSetRequestedIndex(int32_t aRequestedIndex) {
-  MOZ_ASSERT(aRequestedIndex >= -1 && aRequestedIndex < Length());
-  mRequestedIndex = aRequestedIndex;
-}
-
 NS_IMETHODIMP
 nsSHistory::GetEntryAtIndex(int32_t aIndex, nsISHEntry** aResult) {
   NS_ENSURE_ARG_POINTER(aResult);
 
   if (aIndex < 0 || aIndex >= Length()) {
     return NS_ERROR_FAILURE;
   }
 
rename from dom/base/contentAreaDropListener.js
rename to dom/base/ContentAreaDropListener.jsm
--- a/dom/base/contentAreaDropListener.js
+++ b/dom/base/ContentAreaDropListener.jsm
@@ -1,14 +1,13 @@
 /* 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/. */
 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
 
 // This component is used for handling dragover and drop of urls.
 //
 // It checks to see whether a drop of a url is allowed. For instance, a url
 // cannot be dropped if it is not a valid uri or the source of the drag cannot
 // access the uri. This prevents, for example, a source document from tricking
 // the user into dragging a chrome url.
@@ -310,10 +309,9 @@ ContentAreaDropListener.prototype =
       return false;
 
     return ownerDoc.defaultView
                    .windowUtils
                    .isNodeDisabledForEvents(aEvent.originalTarget);
   }
 };
 
-var components = [ContentAreaDropListener];
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
+var EXPORTED_SYMBOLS = ["ContentAreaDropListener"];
rename from dom/base/ProcessSelector.js
rename to dom/base/ProcessSelector.jsm
--- a/dom/base/ProcessSelector.js
+++ b/dom/base/ProcessSelector.jsm
@@ -1,14 +1,12 @@
 /* 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/. */
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
 // 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:   ChromeUtils.generateQI([Ci.nsIContentProcessProvider]),
@@ -63,10 +61,9 @@ MinTabSelector.prototype = {
         candidate = i;
       }
     }
 
     return candidate;
   },
 };
 
-var components = [RandomSelector, MinTabSelector];
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
+var EXPORTED_SYMBOLS = ["RandomSelector", "MinTabSelector"]
deleted file mode 100644
--- a/dom/base/ProcessSelector.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-component {c616fcfd-9737-41f1-aa74-cee72a38f91b} ProcessSelector.js
-component {2dc08eaf-6eef-4394-b1df-a3a927c1290b} ProcessSelector.js
-contract @mozilla.org/ipc/processselector;1 {2dc08eaf-6eef-4394-b1df-a3a927c1290b}
rename from dom/base/SlowScriptDebug.js
rename to dom/base/SlowScriptDebug.jsm
--- a/dom/base/SlowScriptDebug.js
+++ b/dom/base/SlowScriptDebug.jsm
@@ -1,24 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const {XPCOMUtils} = 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: 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; },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SlowScriptDebug]);
+var EXPORTED_SYMBOLS = ["SlowScriptDebug"];
deleted file mode 100644
--- a/dom/base/SlowScriptDebug.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {e740ddb4-18b4-4aac-8ae1-9b0f4320769d} SlowScriptDebug.js
-contract @mozilla.org/dom/slow-script-debug;1 {e740ddb4-18b4-4aac-8ae1-9b0f4320769d}
--- a/dom/base/ThirdPartyUtil.cpp
+++ b/dom/base/ThirdPartyUtil.cpp
@@ -78,42 +78,30 @@ nsresult ThirdPartyUtil::IsThirdPartyInt
   LOG(("ThirdPartyUtil::IsThirdPartyInternal %s =? %s", aFirstDomain.get(),
        secondDomain.get()));
   if (NS_FAILED(rv)) return rv;
 
   *aResult = IsThirdPartyInternal(aFirstDomain, secondDomain);
   return NS_OK;
 }
 
+// Get the URI associated with a window.
 NS_IMETHODIMP
-ThirdPartyUtil::GetPrincipalFromWindow(mozIDOMWindowProxy* aWin,
-                                       nsIPrincipal** result) {
+ThirdPartyUtil::GetURIFromWindow(mozIDOMWindowProxy* aWin, nsIURI** result) {
+  nsresult rv;
   nsCOMPtr<nsIScriptObjectPrincipal> scriptObjPrin = do_QueryInterface(aWin);
   if (!scriptObjPrin) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  nsCOMPtr<nsIPrincipal> prin = scriptObjPrin->GetPrincipal();
+  nsIPrincipal* prin = scriptObjPrin->GetPrincipal();
   if (!prin) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  prin.forget(result);
-  return NS_OK;
-}
-
-// Get the URI associated with a window.
-NS_IMETHODIMP
-ThirdPartyUtil::GetURIFromWindow(mozIDOMWindowProxy* aWin, nsIURI** result) {
-  nsCOMPtr<nsIPrincipal> prin;
-  nsresult rv = GetPrincipalFromWindow(aWin, getter_AddRefs(prin));
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
   if (prin->GetIsNullPrincipal()) {
     LOG(("ThirdPartyUtil::GetURIFromWindow can't use null principal\n"));
     return NS_ERROR_INVALID_ARG;
   }
 
   rv = prin->GetURI(result);
   return rv;
 }
new file mode 100644
--- /dev/null
+++ b/dom/base/components.conf
@@ -0,0 +1,31 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{1f34bc80-1bc7-11d6-a384-d705dd0746fc}',
+        'contract_ids': ['@mozilla.org/content/dropped-link-handler;1'],
+        'jsm': 'resource://gre/modules/ContentAreaDropListener.jsm',
+        'constructor': 'ContentAreaDropListener',
+    },
+    {
+        'cid': '{c616fcfd-9737-41f1-aa74-cee72a38f91b}',
+        'jsm': 'resource://gre/modules/ProcessSelector.jsm',
+        'constructor': 'RandomSelector',
+    },
+    {
+        'cid': '{2dc08eaf-6eef-4394-b1df-a3a927c1290b}',
+        'contract_ids': ['@mozilla.org/ipc/processselector;1'],
+        'jsm': 'resource://gre/modules/ProcessSelector.jsm',
+        'constructor': 'MinTabSelector',
+    },
+    {
+        'cid': '{e740ddb4-18b4-4aac-8ae1-9b0f4320769d}',
+        'contract_ids': ['@mozilla.org/dom/slow-script-debug;1'],
+        'jsm': 'resource://gre/modules/SlowScriptDebug.jsm',
+        'constructor': 'SlowScriptDebug',
+    },
+]
deleted file mode 100644
--- a/dom/base/contentAreaDropListener.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {1f34bc80-1bc7-11d6-a384-d705dd0746fc} contentAreaDropListener.js
-contract @mozilla.org/content/dropped-link-handler;1 {1f34bc80-1bc7-11d6-a384-d705dd0746fc}
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -447,28 +447,26 @@ SOURCES += [
 ]
 
 # Are we targeting x86-32 or x86-64?  If so, we want to include SSE2 code for
 # nsTextFragment.cpp
 if CONFIG['INTEL_ARCHITECTURE']:
     SOURCES += ['nsTextFragmentSSE2.cpp']
     SOURCES['nsTextFragmentSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
 
-EXTRA_COMPONENTS += [
-    'contentAreaDropListener.js',
-    'contentAreaDropListener.manifest',
-    'ProcessSelector.js',
-    'ProcessSelector.manifest',
-    'SlowScriptDebug.js',
-    'SlowScriptDebug.manifest',
+EXTRA_JS_MODULES += [
+    'ContentAreaDropListener.jsm',
+    'DOMRequestHelper.jsm',
+    'IndexedDBHelper.jsm',
+    'ProcessSelector.jsm',
+    'SlowScriptDebug.jsm',
 ]
 
-EXTRA_JS_MODULES += [
-    'DOMRequestHelper.jsm',
-    'IndexedDBHelper.jsm',
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 LOCAL_INCLUDES += [
     '../battery',
     '../events',
     '../media',
     '../network',
     '/caps',
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -302,17 +302,17 @@ void nsAttrValue::SetTo(const nsAttrValu
         cont->mValue.mIntMargin =
             new nsIntMargin(*otherCont->mValue.mIntMargin);
       break;
     }
     default: {
       if (IsSVGType(otherCont->mType)) {
         // All SVG types are just pointers to classes and will therefore have
         // the same size so it doesn't really matter which one we assign
-        cont->mValue.mSVGAngle = otherCont->mValue.mSVGAngle;
+        cont->mValue.mSVGLength = otherCont->mValue.mSVGLength;
       } else {
         MOZ_ASSERT_UNREACHABLE("unknown type stored in MiscContainer");
       }
       break;
     }
   }
 
   void* otherPtr = MISC_STR_PTR(otherCont);
@@ -393,18 +393,18 @@ void nsAttrValue::SetToSerialized(const 
     nsAutoString val;
     aOther.ToString(val);
     SetTo(val);
   } else {
     SetTo(aOther);
   }
 }
 
-void nsAttrValue::SetTo(const SVGAngle& aValue, const nsAString* aSerialized) {
-  SetSVGType(eSVGAngle, &aValue, aSerialized);
+void nsAttrValue::SetTo(const SVGOrient& aValue, const nsAString* aSerialized) {
+  SetSVGType(eSVGOrient, &aValue, aSerialized);
 }
 
 void nsAttrValue::SetTo(const SVGIntegerPair& aValue,
                         const nsAString* aSerialized) {
   SetSVGType(eSVGIntegerPair, &aValue, aSerialized);
 }
 
 void nsAttrValue::SetTo(const nsSVGLength2& aValue,
@@ -558,23 +558,23 @@ void nsAttrValue::ToString(nsAString& aR
 
       break;
     }
     case eDoubleValue: {
       aResult.Truncate();
       aResult.AppendFloat(GetDoubleValue());
       break;
     }
-    case eSVGAngle: {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGAngle,
+    case eSVGIntegerPair: {
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGIntegerPair,
                                     aResult);
       break;
     }
-    case eSVGIntegerPair: {
-      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGIntegerPair,
+    case eSVGOrient: {
+      SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGOrient,
                                     aResult);
       break;
     }
     case eSVGLength: {
       SVGAttrValueWrapper::ToString(GetMiscContainer()->mValue.mSVGLength,
                                     aResult);
       break;
     }
@@ -782,17 +782,17 @@ uint32_t nsAttrValue::HashValue() const 
       return cont->mDoubleValue;
     }
     case eIntMarginValue: {
       return NS_PTR_TO_INT32(cont->mValue.mIntMargin);
     }
     default: {
       if (IsSVGType(cont->mType)) {
         // All SVG types are just pointers to classes so we can treat them alike
-        return NS_PTR_TO_INT32(cont->mValue.mSVGAngle);
+        return NS_PTR_TO_INT32(cont->mValue.mSVGLength);
       }
       MOZ_ASSERT_UNREACHABLE("unknown type stored in MiscContainer");
       return 0;
     }
   }
 }
 
 bool nsAttrValue::Equals(const nsAttrValue& aOther) const {
@@ -1602,17 +1602,17 @@ void nsAttrValue::SetSVGType(ValueType a
                              const nsAString* aSerialized) {
   MOZ_ASSERT(IsSVGType(aType), "Not an SVG type");
 
   MiscContainer* cont = EnsureEmptyMiscContainer();
   // All SVG types are just pointers to classes so just setting any of them
   // will do. We'll lose type-safety but the signature of the calling
   // function should ensure we don't get anything unexpected, and once we
   // stick aValue in a union we lose type information anyway.
-  cont->mValue.mSVGAngle = static_cast<const SVGAngle*>(aValue);
+  cont->mValue.mSVGLength = static_cast<const nsSVGLength2*>(aValue);
   cont->mType = aType;
   SetMiscAtomOrString(aSerialized);
 }
 
 MiscContainer* nsAttrValue::ClearMiscContainer() {
   MiscContainer* cont = nullptr;
   if (BaseType() == eOtherBase) {
     cont = GetMiscContainer();
--- a/dom/base/nsAttrValue.h
+++ b/dom/base/nsAttrValue.h
@@ -96,19 +96,19 @@ class nsAttrValue {
     // Values below here won't matter, they'll be always stored in the 'misc'
     // struct.
     eCSSDeclaration = 0x10,
     eURL,
     eImage,
     eAtomArray,
     eDoubleValue,
     eIntMarginValue,
-    eSVGAngle,
-    eSVGTypesBegin = eSVGAngle,
     eSVGIntegerPair,
+    eSVGTypesBegin = eSVGIntegerPair,
+    eSVGOrient,
     eSVGLength,
     eSVGLengthList,
     eSVGNumberList,
     eSVGNumberPair,
     eSVGPathData,
     eSVGPointList,
     eSVGPreserveAspectRatio,
     eSVGStringList,
@@ -146,17 +146,17 @@ class nsAttrValue {
   void SetTo(nsAtom* aValue);
   void SetTo(int16_t aInt);
   void SetTo(int32_t aInt, const nsAString* aSerialized);
   void SetTo(double aValue, const nsAString* aSerialized);
   void SetTo(already_AddRefed<mozilla::DeclarationBlock> aValue,
              const nsAString* aSerialized);
   void SetTo(nsIURI* aValue, const nsAString* aSerialized);
   void SetTo(const nsIntMargin& aValue);
-  void SetTo(const mozilla::SVGAngle& aValue, const nsAString* aSerialized);
+  void SetTo(const mozilla::SVGOrient& aValue, const nsAString* aSerialized);
   void SetTo(const mozilla::SVGIntegerPair& aValue,
              const nsAString* aSerialized);
   void SetTo(const nsSVGLength2& aValue, const nsAString* aSerialized);
   void SetTo(const mozilla::SVGLengthList& aValue,
              const nsAString* aSerialized);
   void SetTo(const mozilla::SVGNumberList& aValue,
              const nsAString* aSerialized);
   void SetTo(const mozilla::SVGNumberPair& aValue,
--- a/dom/base/nsAttrValueInlines.h
+++ b/dom/base/nsAttrValueInlines.h
@@ -39,22 +39,22 @@ struct MiscContainer final {
         int32_t mInteger;
         nscolor mColor;
         uint32_t mEnumValue;
         int32_t mPercent;
         mozilla::DeclarationBlock* mCSSDeclaration;
         nsIURI* mURL;
         mozilla::AtomArray* mAtomArray;
         nsIntMargin* mIntMargin;
-        const mozilla::SVGAngle* mSVGAngle;
         const mozilla::SVGIntegerPair* mSVGIntegerPair;
         const nsSVGLength2* mSVGLength;
         const mozilla::SVGLengthList* mSVGLengthList;
         const mozilla::SVGNumberList* mSVGNumberList;
         const mozilla::SVGNumberPair* mSVGNumberPair;
+        const mozilla::SVGOrient* mSVGOrient;
         const mozilla::SVGPathData* mSVGPathData;
         const mozilla::SVGPointList* mSVGPointList;
         const mozilla::SVGAnimatedPreserveAspectRatio* mSVGPreserveAspectRatio;
         const mozilla::SVGStringList* mSVGStringList;
         const mozilla::SVGTransformList* mSVGTransformList;
         const mozilla::SVGViewBox* mSVGViewBox;
       };
       uint32_t mRefCount : 31;
--- a/dom/base/test/test_bug715041.xul
+++ b/dom/base/test/test_bug715041.xul
@@ -715,17 +715,17 @@ target="_blank">Mozilla Bug 715041</a>
     try {
       componentMgr.unregisterFactory(idleServiceCID, idleServiceObj);
     }
     catch(err) {
       dump("test_bug715041.xul: ShiftLocalTimerBackCleanUp() Failed to unregister factory, mock idle service!\n");
     }
 
     try {
-      componentMgr.registerFactory(oldIdleServiceCID, "Re registering old idle service", idleServiceContractID, oldIdleServiceFactoryObj);
+      componentMgr.registerFactory(oldIdleServiceCID, "Re registering old idle service", idleServiceContractID, null);
     }
     catch(err) {
       dump("test_bug715041.xul: ShiftLocalTimerBackCleanUp() Failed to register factory, original idle service!\n");
     }
 
     SimpleTest.finish();
   }
 
@@ -780,23 +780,16 @@ target="_blank">Mozilla Bug 715041</a>
   try {
     var oldIdleServiceCID = componentMgr.contractIDToCID(idleServiceContractID);
   }
   catch(err) {
     dump("test_bug715041.xul: Failed to convert ID to CID for old idle service.\n");
   }
 
   try {
-    componentMgr.unregisterFactory(oldIdleServiceCID, oldIdleServiceFactoryObj);
-  }
-  catch(err) {
-    dump("test_bug715041.xul: Failed to unregister old idle service factory object!\n");
-  }
-
-  try {
     componentMgr.registerFactory(idleServiceCID, "Test Simple Idle/Back Notifications", idleServiceContractID, idleServiceObj);
   }
   catch(err) {
     dump("test_bug715041.xul: Failed to register mock idle service.\n");
   }
 
   SimpleTest.waitForExplicitFinish();
   SimpleTest.requestLongerTimeout(10);
--- a/dom/base/test/test_bug715041_removal.xul
+++ b/dom/base/test/test_bug715041_removal.xul
@@ -760,17 +760,17 @@ target="_blank">Mozilla Bug 715041</a>
     try {
       componentMgr.unregisterFactory(idleServiceCID, idleServiceObj);
     }
     catch(err) {
       dump("test_bug715041_removal.xul: RemoveLastAddLastCleanUp() Failed to unregister factory, mock idle service!\n");
     }
 
     try {
-      componentMgr.registerFactory(oldIdleServiceCID, "Re registering old idle service", idleServiceContractID, oldIdleServiceFactoryObj);
+      componentMgr.registerFactory(oldIdleServiceCID, "Re registering old idle service", idleServiceContractID, null);
     }
     catch(err) {
       dump("test_bug715041_removal.xul: RemoveLastAddLastCleanUp() Failed to register factory, original idle service!\n");
     }
 
     dump("JS RemoveLastAddLastCleanUp() DONE\n");
     dump("Finishing testing idle API.\n");
     SimpleTest.finish();
@@ -808,23 +808,16 @@ target="_blank">Mozilla Bug 715041</a>
   try {
     var oldIdleServiceCID = componentMgr.contractIDToCID(idleServiceContractID);
   }
   catch(err) {
     dump("test_bug715041._removalxul: Failed to convert ID to CID for old idle service.\n");
   }
 
   try {
-    componentMgr.unregisterFactory(oldIdleServiceCID, oldIdleServiceFactoryObj);
-  }
-  catch(err) {
-    dump("test_bug715041_removal.xul: Failed to unregister old idle service factory object!\n");
-  }
-
-  try {
     componentMgr.registerFactory(idleServiceCID, "Test Simple Idle/Back Notifications", idleServiceContractID, idleServiceObj);
   }
   catch(err) {
     dump("test_bug715041_removal.xul: Failed to register mock idle service.\n");
   }
 
   //test case enabled
   var RemoveLocalIdleObserverWhileIdleEnabled = true;
rename from dom/browser-element/BrowserElementParent.js
rename to dom/browser-element/BrowserElementParent.jsm
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -5,17 +5,16 @@
 "use strict";
 
 /* BrowserElementParent injects script to listen for certain events in the
  * child.  We then listen to messages from the child script and take
  * appropriate action here in the parent.
  */
 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {BrowserElementPromptService} = ChromeUtils.import("resource://gre/modules/BrowserElementPromptService.jsm");
 
 function debug(msg) {
   //dump("BrowserElementParent - " + msg + "\n");
 }
 
 function getIntPref(prefName, def) {
   try {
@@ -617,9 +616,9 @@ BrowserElementParent.prototype = {
       break;
     default:
       debug('Unknown topic: ' + topic);
       break;
     };
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParent]);
+var EXPORTED_SYMBOLS = ["BrowserElementParent"];
deleted file mode 100644
--- a/dom/browser-element/BrowserElementParent.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {9f171ac4-0939-4ef8-b360-3408aedc3060} BrowserElementParent.js
-contract @mozilla.org/dom/browser-element-api;1 {9f171ac4-0939-4ef8-b360-3408aedc3060}
--- a/dom/browser-element/BrowserElementPromptService.jsm
+++ b/dom/browser-element/BrowserElementPromptService.jsm
@@ -591,18 +591,16 @@ var BrowserElementPromptService = {
     var newCID = BrowserElementPromptFactory.prototype.classID;
     var oldFactory = Cm.getClassObject(Cc[contractID], Ci.nsIFactory);
 
     if (oldCID == newCID) {
       debug("WARNING: Wrapped prompt factory is already installed!");
       return;
     }
 
-    Cm.unregisterFactory(oldCID, oldFactory);
-
     var oldInstance = oldFactory.createInstance(null, Ci.nsIPromptFactory);
     var newInstance = new BrowserElementPromptFactory(oldInstance);
 
     var newFactory = {
       createInstance: function(outer, iid) {
         if (outer != null) {
           throw Cr.NS_ERROR_NO_AGGREGATION;
         }
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/components.conf
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{9f171ac4-0939-4ef8-b360-3408aedc3060}',
+        'contract_ids': ['@mozilla.org/dom/browser-element-api;1'],
+        'jsm': 'resource://gre/modules/BrowserElementParent.jsm',
+        'constructor': 'BrowserElementParent',
+    },
+]
--- a/dom/browser-element/moz.build
+++ b/dom/browser-element/moz.build
@@ -16,23 +16,23 @@ SOURCES += [
 ]
 
 XPIDL_SOURCES += [
     'nsIBrowserElementAPI.idl',
 ]
 
 XPIDL_MODULE = 'browser-element'
 
-EXTRA_COMPONENTS += [
-    'BrowserElementParent.js',
-    'BrowserElementParent.manifest',
+EXTRA_JS_MODULES += [
+    'BrowserElementParent.jsm',
+    'BrowserElementPromptService.jsm',
 ]
 
-EXTRA_JS_MODULES += [
-    'BrowserElementPromptService.jsm',
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/html',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
deleted file mode 100644
--- a/dom/console/ConsoleAPI.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {96cf7855-dfa9-4c6d-8276-f9705b4890f2} ConsoleAPIStorage.js
-contract @mozilla.org/consoleAPI-storage;1 {96cf7855-dfa9-4c6d-8276-f9705b4890f2}
rename from dom/console/ConsoleAPIStorage.js
rename to dom/console/ConsoleAPIStorage.jsm
--- a/dom/console/ConsoleAPIStorage.js
+++ b/dom/console/ConsoleAPIStorage.jsm
@@ -1,20 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-// This constant tells how many messages to process in a single timer execution.
-const MESSAGES_IN_INTERVAL = 1500;
-
 const STORAGE_MAX_EVENTS = 1000;
 
 var _consoleStorage = new Map();
 
 const CONSOLEAPISTORAGE_CID = Components.ID("{96cf7855-dfa9-4c6d-8276-f9705b4890f2}");
 
 /**
  * The ConsoleAPIStorage is meant to cache window.console API calls for later
@@ -137,9 +133,9 @@ ConsoleAPIStorageService.prototype = {
       _consoleStorage.delete(aId);
     } else {
       _consoleStorage.clear();
       Services.obs.notifyObservers(null, "console-storage-reset");
     }
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ConsoleAPIStorageService]);
+var EXPORTED_SYMBOLS = ["ConsoleAPIStorageService"];
new file mode 100644
--- /dev/null
+++ b/dom/console/components.conf
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{96cf7855-dfa9-4c6d-8276-f9705b4890f2}',
+        'contract_ids': ['@mozilla.org/consoleAPI-storage;1'],
+        'jsm': 'resource://gre/modules/ConsoleAPIStorage.jsm',
+        'constructor': 'ConsoleAPIStorageService',
+    },
+]
--- a/dom/console/moz.build
+++ b/dom/console/moz.build
@@ -29,19 +29,22 @@ EXPORTS.mozilla.dom += [
 
 UNIFIED_SOURCES += [
     'Console.cpp',
     'ConsoleInstance.cpp',
     'ConsoleReportCollector.cpp',
     'ConsoleUtils.cpp',
 ]
 
-EXTRA_COMPONENTS += [
-    'ConsoleAPI.manifest',
-    'ConsoleAPIStorage.js',
+EXTRA_JS_MODULES += [
+    'ConsoleAPIStorage.jsm',
+]
+
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 LOCAL_INCLUDES += [
     '/docshell/base',
     '/dom/base',
     '/js/xpconnect/src',
 ]
 
rename from dom/html/htmlMenuBuilder.js
rename to dom/html/HTMLMenuBuilder.jsm
--- a/dom/html/htmlMenuBuilder.js
+++ b/dom/html/HTMLMenuBuilder.jsm
@@ -1,16 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // This component is used to build the menus for the HTML contextmenu attribute.
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
 // A global value that is used to identify each menu item. It is
 // incremented with each one that is found.
 var gGeneratedId = 1;
 
 function HTMLMenuBuilder() {
   this.currentNode = null;
   this.root = null;
   this.items = {};
@@ -126,9 +124,9 @@ HTMLMenuBuilder.prototype =
   click: function(id) {
     let item = this.items[id];
     if (item) {
       item.click();
     }
   }
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HTMLMenuBuilder]);
+var EXPORTED_SYMBOLS = ["HTMLMenuBuilder"];
new file mode 100644
--- /dev/null
+++ b/dom/html/components.conf
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{51c65f5d-0de5-4edc-9058-60e50cef77f8}',
+        'contract_ids': ['@mozilla.org/content/html-menu-builder;1'],
+        'jsm': 'resource://gre/modules/HTMLMenuBuilder.jsm',
+        'constructor': 'HTMLMenuBuilder',
+    },
+]
deleted file mode 100644
--- a/dom/html/htmlMenuBuilder.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-component {51c65f5d-0de5-4edc-9058-60e50cef77f8} htmlMenuBuilder.js
-contract @mozilla.org/content/html-menu-builder;1 {51c65f5d-0de5-4edc-9058-60e50cef77f8}
-
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -222,19 +222,22 @@ UNIFIED_SOURCES += [
     'VideoDocument.cpp',
 ]
 
 SOURCES += [
     # Includes npapi.h.
     'PluginDocument.cpp',
 ]
 
-EXTRA_COMPONENTS += [
-    'htmlMenuBuilder.js',
-    'htmlMenuBuilder.manifest'
+EXTRA_JS_MODULES += [
+    'HTMLMenuBuilder.jsm',
+]
+
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/caps',
     '/docshell/base',
     '/dom/base',
--- a/dom/ipc/WindowGlobalChild.h
+++ b/dom/ipc/WindowGlobalChild.h
@@ -15,17 +15,16 @@ class nsGlobalWindowInner;
 class nsDocShell;
 
 namespace mozilla {
 namespace dom {
 
 class BrowsingContext;
 class WindowGlobalParent;
 class JSWindowActorChild;
-class TabChild;
 
 /**
  * Actor for a single nsGlobalWindowInner. This actor is used to communicate
  * information to the parent process asynchronously.
  */
 class WindowGlobalChild : public nsWrapperCache, public PWindowGlobalChild {
   friend class PWindowGlobalChild;
 
rename from dom/media/PeerConnection.js
rename to dom/media/PeerConnection.jsm
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.jsm
@@ -1,29 +1,25 @@
 /* jshint moz:true, browser:true */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "PeerConnectionIdp",
   "resource://gre/modules/media/PeerConnectionIdp.jsm");
 ChromeUtils.defineModuleGetter(this, "convertToRTCStatsReport",
   "resource://gre/modules/media/RTCStatsReport.jsm");
-ChromeUtils.defineModuleGetter(this, "AppConstants",
-  "resource://gre/modules/AppConstants.jsm");
 
 const PC_CONTRACT = "@mozilla.org/dom/peerconnection;1";
 const PC_OBS_CONTRACT = "@mozilla.org/dom/peerconnectionobserver;1";
 const PC_ICE_CONTRACT = "@mozilla.org/dom/rtcicecandidate;1";
 const PC_SESSION_CONTRACT = "@mozilla.org/dom/rtcsessiondescription;1";
-const PC_MANAGER_CONTRACT = "@mozilla.org/dom/peerconnectionmanager;1";
 const PC_STATS_CONTRACT = "@mozilla.org/dom/rtcstatsreport;1";
 const PC_STATIC_CONTRACT = "@mozilla.org/dom/peerconnectionstatic;1";
 const PC_SENDER_CONTRACT = "@mozilla.org/dom/rtpsender;1";
 const PC_RECEIVER_CONTRACT = "@mozilla.org/dom/rtpreceiver;1";
 const PC_TRANSCEIVER_CONTRACT = "@mozilla.org/dom/rtptransceiver;1";
 const PC_COREQUEST_CONTRACT = "@mozilla.org/dom/createofferrequest;1";
 const PC_DTMF_SENDER_CONTRACT = "@mozilla.org/dom/rtcdtmfsender;1";
 
@@ -2384,22 +2380,21 @@ class CreateOfferRequest {
   }
 }
 setupPrototype(CreateOfferRequest, {
   classID: PC_COREQUEST_CID,
   contractID: PC_COREQUEST_CONTRACT,
   QueryInterface: ChromeUtils.generateQI([]),
 });
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
-  [GlobalPCList,
-   RTCDTMFSender,
-   RTCIceCandidate,
-   RTCSessionDescription,
-   RTCPeerConnection,
-   RTCPeerConnectionStatic,
-   RTCRtpReceiver,
-   RTCRtpSender,
-   RTCRtpTransceiver,
-   RTCStatsReport,
-   PeerConnectionObserver,
-   CreateOfferRequest]
-);
+var EXPORTED_SYMBOLS =
+  ["GlobalPCList",
+   "RTCDTMFSender",
+   "RTCIceCandidate",
+   "RTCSessionDescription",
+   "RTCPeerConnection",
+   "RTCPeerConnectionStatic",
+   "RTCRtpReceiver",
+   "RTCRtpSender",
+   "RTCRtpTransceiver",
+   "RTCStatsReport",
+   "PeerConnectionObserver",
+   "CreateOfferRequest"];
deleted file mode 100644
--- a/dom/media/PeerConnection.manifest
+++ /dev/null
@@ -1,23 +0,0 @@
-component {bdc2e533-b308-4708-ac8e-a8bfade6d851} PeerConnection.js
-component {d1748d4c-7f6a-4dc5-add6-d55b7678537e} PeerConnection.js
-component {02b9970c-433d-4cc2-923d-f7028ac66073} PeerConnection.js
-component {1775081b-b62d-4954-8ffe-a067bbf508a7} PeerConnection.js
-component {7293e901-2be3-4c02-b4bd-cbef6fc24f78} PeerConnection.js
-component {7fe6e18b-0da3-4056-bf3b-440ef3809e06} PeerConnection.js
-component {0fb47c47-a205-4583-a9fc-cbadf8c95880} PeerConnection.js
-component {4fff5d46-d827-4cd4-a970-8fd53977440e} PeerConnection.js
-component {d974b814-8fde-411c-8c45-b86791b81030} PeerConnection.js
-component {74b2122d-65a8-4824-aa9e-3d664cb75dc2} PeerConnection.js
-component {3610C242-654E-11E6-8EC0-6D1BE389A607} PeerConnection.js
-
-contract @mozilla.org/dom/peerconnection;1 {bdc2e533-b308-4708-ac8e-a8bfade6d851}
-contract @mozilla.org/dom/peerconnectionobserver;1 {d1748d4c-7f6a-4dc5-add6-d55b7678537e}
-contract @mozilla.org/dom/rtcdtmfsender;1 {3610C242-654E-11E6-8EC0-6D1BE389A607}
-contract @mozilla.org/dom/rtcicecandidate;1 {02b9970c-433d-4cc2-923d-f7028ac66073}
-contract @mozilla.org/dom/rtcsessiondescription;1 {1775081b-b62d-4954-8ffe-a067bbf508a7}
-contract @mozilla.org/dom/peerconnectionmanager;1 {7293e901-2be3-4c02-b4bd-cbef6fc24f78}
-contract @mozilla.org/dom/rtcstatsreport;1 {7fe6e18b-0da3-4056-bf3b-440ef3809e06}
-contract @mozilla.org/dom/peerconnectionstatic;1 {0fb47c47-a205-4583-a9fc-cbadf8c95880}
-contract @mozilla.org/dom/rtpsender;1 {4fff5d46-d827-4cd4-a970-8fd53977440e}
-contract @mozilla.org/dom/rtpreceiver;1 {d974b814-8fde-411c-8c45-b86791b81030}
-contract @mozilla.org/dom/createofferrequest;1 {74b2122d-65a8-4824-aa9e-3d664cb75dc2}
--- a/dom/media/bridge/MediaModule.cpp
+++ b/dom/media/bridge/MediaModule.cpp
@@ -1,59 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/ModuleUtils.h"
-#include "nsIClassInfoImpl.h"
+#include "mozilla/Components.h"
 
 #ifdef MOZ_WEBRTC
-
 #  include "PeerConnectionImpl.h"
 
-#  define PEERCONNECTION_CID                           \
-    {                                                  \
-      0xb93af7a1, 0x3411, 0x44a8, {                    \
-        0xbd, 0x0a, 0x8a, 0xf3, 0xdd, 0xe4, 0xd8, 0xd8 \
-      }                                                \
-    }
-
-#  define PEERCONNECTION_CONTRACTID "@mozilla.org/peerconnection;1"
-
-#  include "stun_socket_filter.h"
-
-NS_DEFINE_NAMED_CID(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CID)
-NS_DEFINE_NAMED_CID(NS_STUN_TCP_SOCKET_FILTER_HANDLER_CID)
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsStunUDPSocketFilterHandler)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsStunTCPSocketFilterHandler)
-
-namespace mozilla {
-// Factory defined in mozilla::, defines mozilla::PeerConnectionImplConstructor
-NS_GENERIC_FACTORY_CONSTRUCTOR(PeerConnectionImpl)
-}  // namespace mozilla
+using namespace mozilla;
 
-// Defines kPEERCONNECTION_CID
-NS_DEFINE_NAMED_CID(PEERCONNECTION_CID);
-
-static const mozilla::Module::CIDEntry kCIDs[] = {
-    {&kPEERCONNECTION_CID, false, nullptr,
-     mozilla::PeerConnectionImplConstructor},
-    {&kNS_STUN_UDP_SOCKET_FILTER_HANDLER_CID, false, nullptr,
-     nsStunUDPSocketFilterHandlerConstructor},
-    {&kNS_STUN_TCP_SOCKET_FILTER_HANDLER_CID, false, nullptr,
-     nsStunTCPSocketFilterHandlerConstructor},
-    {nullptr}};
-
-static const mozilla::Module::ContractIDEntry kContracts[] = {
-    {PEERCONNECTION_CONTRACTID, &kPEERCONNECTION_CID},
-    {NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID,
-     &kNS_STUN_UDP_SOCKET_FILTER_HANDLER_CID},
-    {NS_STUN_TCP_SOCKET_FILTER_HANDLER_CONTRACTID,
-     &kNS_STUN_TCP_SOCKET_FILTER_HANDLER_CID},
-    {nullptr}};
-
-static const mozilla::Module kModule = {mozilla::Module::kVersion, kCIDs,
-                                        kContracts};
-
-NSMODULE_DEFN(peerconnection) = &kModule;
+NS_IMPL_COMPONENT_FACTORY(mozilla::PeerConnectionImpl) {
+  return do_AddRef(new PeerConnectionImpl()).downcast<nsISupports>();
+}
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/media/bridge/components.conf
@@ -0,0 +1,25 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{b93af7a1-3411-44a8-bd0a-8af3dde4d8d8}',
+        'contract_ids': ['@mozilla.org/peerconnection;1'],
+        'type': 'mozilla::PeerConnectionImpl',
+    },
+    {
+        'cid': '{9fea635a-2fc2-4d08-9721-d238d3f52f92}',
+        'contract_ids': ['@mozilla.org/network/tcp-filter-handler;1?name=stun'],
+        'type': 'nsStunTCPSocketFilterHandler',
+        'headers': ['mtransport/stun_socket_filter.h'],
+    },
+    {
+        'cid': '{3e43ee93-829e-4ea6-a34e-62d9e4c9f993}',
+        'contract_ids': ['@mozilla.org/network/udp-filter-handler;1?name=stun'],
+        'type': 'nsStunUDPSocketFilterHandler',
+        'headers': ['mtransport/stun_socket_filter.h'],
+    },
+]
--- a/dom/media/bridge/moz.build
+++ b/dom/media/bridge/moz.build
@@ -21,12 +21,17 @@ LOCAL_INCLUDES += [
     '/media/webrtc/',
     '/media/webrtc/signaling/src/common/time_profiling',
     '/media/webrtc/signaling/src/media-conduit',
     '/media/webrtc/signaling/src/mediapipeline',
     '/media/webrtc/signaling/src/peerconnection',
     '/media/webrtc/trunk/',
 ]
 
+if CONFIG['MOZ_WEBRTC']:
+    XPCOM_MANIFESTS += [
+        'components.conf',
+    ]
+
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
new file mode 100644
--- /dev/null
+++ b/dom/media/components.conf
@@ -0,0 +1,74 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{bdc2e533-b308-4708-ac8e-a8bfade6d851}',
+        'contract_ids': ['@mozilla.org/dom/peerconnection;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'RTCPeerConnection',
+    },
+    {
+        'cid': '{d1748d4c-7f6a-4dc5-add6-d55b7678537e}',
+        'contract_ids': ['@mozilla.org/dom/peerconnectionobserver;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'PeerConnectionObserver',
+    },
+    {
+        'cid': '{3610C242-654E-11E6-8EC0-6D1BE389A607}',
+        'contract_ids': ['@mozilla.org/dom/rtcdtmfsender;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'RTCDTMFSender',
+    },
+    {
+        'cid': '{02b9970c-433d-4cc2-923d-f7028ac66073}',
+        'contract_ids': ['@mozilla.org/dom/rtcicecandidate;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'RTCIceCandidate',
+    },
+    {
+        'cid': '{1775081b-b62d-4954-8ffe-a067bbf508a7}',
+        'contract_ids': ['@mozilla.org/dom/rtcsessiondescription;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'RTCSessionDescription',
+    },
+    {
+        'cid': '{7293e901-2be3-4c02-b4bd-cbef6fc24f78}',
+        'contract_ids': ['@mozilla.org/dom/peerconnectionmanager;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'GlobalPCList',
+    },
+    {
+        'cid': '{7fe6e18b-0da3-4056-bf3b-440ef3809e06}',
+        'contract_ids': ['@mozilla.org/dom/rtcstatsreport;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'RTCStatsReport',
+    },
+    {
+        'cid': '{0fb47c47-a205-4583-a9fc-cbadf8c95880}',
+        'contract_ids': ['@mozilla.org/dom/peerconnectionstatic;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'RTCPeerConnectionStatic',
+    },
+    {
+        'cid': '{4fff5d46-d827-4cd4-a970-8fd53977440e}',
+        'contract_ids': ['@mozilla.org/dom/rtpsender;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'RTCRtpSender',
+    },
+    {
+        'cid': '{d974b814-8fde-411c-8c45-b86791b81030}',
+        'contract_ids': ['@mozilla.org/dom/rtpreceiver;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'RTCRtpReceiver',
+    },
+    {
+        'cid': '{74b2122d-65a8-4824-aa9e-3d664cb75dc2}',
+        'contract_ids': ['@mozilla.org/dom/createofferrequest;1'],
+        'jsm': 'resource://gre/modules/media/PeerConnection.jsm',
+        'constructor': 'CreateOfferRequest',
+    },
+]
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -301,20 +301,24 @@ SOURCES += [
     'CubebUtils.cpp',
     'DecoderTraits.cpp',
 ]
 
 # Some codec-related code uses multi-character constants, which GCC and clang
 # warn about. Suppress turning this warning into an error.
 SOURCES['DecoderTraits.cpp'].flags += ['-Wno-error=multichar']
 
-EXTRA_COMPONENTS += [
-    'PeerConnection.js',
-    'PeerConnection.manifest',
-]
+if CONFIG['MOZ_WEBRTC']:
+    XPCOM_MANIFESTS += [
+        'components.conf',
+    ]
+
+    EXTRA_JS_MODULES.media += [
+        'PeerConnection.jsm',
+    ]
 
 EXTRA_JS_MODULES.media += [
     'IdpSandbox.jsm',
     'PeerConnectionIdp.jsm',
     'RTCStatsReport.jsm',
 ]
 
 LOCAL_INCLUDES += [
rename from dom/notification/NotificationStorage.js
rename to dom/notification/NotificationStorage.jsm
--- a/dom/notification/NotificationStorage.js
+++ b/dom/notification/NotificationStorage.jsm
@@ -2,21 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const DEBUG = false;
 function debug(s) { dump("-*- NotificationStorage.js: " + s + "\n"); }
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-const NOTIFICATIONSTORAGE_CID = "{37f819b0-0b5c-11e3-8ffd-0800200c9a66}";
-const NOTIFICATIONSTORAGE_CONTRACTID = "@mozilla.org/notificationStorage;1";
-
 ChromeUtils.defineModuleGetter(this, "Services",
                                "resource://gre/modules/Services.jsm");
 
 const kMessageNotificationGetAllOk = "Notification:GetAll:Return:OK";
 const kMessageNotificationGetAllKo = "Notification:GetAll:Return:KO";
 const kMessageNotificationSaveKo   = "Notification:Save:Return:KO";
 const kMessageNotificationDeleteKo = "Notification:Delete:Return:KO";
 
@@ -186,15 +181,13 @@ NotificationStorage.prototype = {
     });
     try {
       Services.tm.dispatchToMainThread(callback.done);
     } catch (e) {
       if (DEBUG) { debug("Error calling callback done: " + e); }
     }
   },
 
-  classID : Components.ID(NOTIFICATIONSTORAGE_CID),
-  contractID : NOTIFICATIONSTORAGE_CONTRACTID,
   QueryInterface: ChromeUtils.generateQI([Ci.nsINotificationStorage]),
 };
 
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NotificationStorage]);
+var EXPORTED_SYMBOLS = ["NotificationStorage"];
deleted file mode 100644
--- a/dom/notification/NotificationStorage.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-# NotificationStorage.js
-component {37f819b0-0b5c-11e3-8ffd-0800200c9a66} NotificationStorage.js
-contract @mozilla.org/notificationStorage;1 {37f819b0-0b5c-11e3-8ffd-0800200c9a66}
new file mode 100644
--- /dev/null
+++ b/dom/notification/components.conf
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{37f819b0-0b5c-11e3-8ffd-0800200c9a66}',
+        'contract_ids': ['@mozilla.org/notificationStorage;1'],
+        'jsm': 'resource://gre/modules/NotificationStorage.jsm',
+        'constructor': 'NotificationStorage',
+    },
+]
--- a/dom/notification/moz.build
+++ b/dom/notification/moz.build
@@ -2,23 +2,23 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files("**"):
     BUG_COMPONENT = ("Toolkit", "Notifications and Alerts")
 
-EXTRA_COMPONENTS += [
-    'NotificationStorage.js',
-    'NotificationStorage.manifest',
+EXTRA_JS_MODULES += [
+    'NotificationDB.jsm',
+    'NotificationStorage.jsm',
 ]
 
-EXTRA_JS_MODULES += [
-    'NotificationDB.jsm'
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 EXPORTS.mozilla.dom += [
     'Notification.h',
     'NotificationEvent.h',
 ]
 
 UNIFIED_SOURCES += [
deleted file mode 100644
--- a/dom/payments/PaymentRequestModule.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- 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/. */
-
-#include "mozilla/ModuleUtils.h"
-#include "PaymentActionResponse.h"
-#include "PaymentRequestData.h"
-#include "PaymentRequestService.h"
-
-using mozilla::dom::BasicCardMethodChangeDetails;
-using mozilla::dom::BasicCardResponseData;
-using mozilla::dom::GeneralMethodChangeDetails;
-using mozilla::dom::GeneralResponseData;
-using mozilla::dom::PaymentAbortActionResponse;
-using mozilla::dom::PaymentCanMakeActionResponse;
-using mozilla::dom::PaymentCompleteActionResponse;
-using mozilla::dom::PaymentRequestService;
-using mozilla::dom::PaymentShowActionResponse;
-using mozilla::dom::payments::PaymentAddress;
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(GeneralResponseData)
-NS_GENERIC_FACTORY_CONSTRUCTOR(BasicCardResponseData)
-NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCanMakeActionResponse)
-NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentAbortActionResponse)
-NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentShowActionResponse)
-NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCompleteActionResponse)
-NS_GENERIC_FACTORY_CONSTRUCTOR(GeneralMethodChangeDetails)
-NS_GENERIC_FACTORY_CONSTRUCTOR(BasicCardMethodChangeDetails)
-NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentAddress)
-NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(PaymentRequestService,
-                                         PaymentRequestService::GetSingleton)
-
-NS_DEFINE_NAMED_CID(NS_GENERAL_RESPONSE_DATA_CID);
-NS_DEFINE_NAMED_CID(NS_BASICCARD_RESPONSE_DATA_CID);
-NS_DEFINE_NAMED_CID(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID);
-NS_DEFINE_NAMED_CID(NS_PAYMENT_ABORT_ACTION_RESPONSE_CID);
-NS_DEFINE_NAMED_CID(NS_PAYMENT_SHOW_ACTION_RESPONSE_CID);
-NS_DEFINE_NAMED_CID(NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID);
-NS_DEFINE_NAMED_CID(NS_GENERAL_CHANGE_DETAILS_CID);
-NS_DEFINE_NAMED_CID(NS_BASICCARD_CHANGE_DETAILS_CID);
-NS_DEFINE_NAMED_CID(NS_PAYMENT_ADDRESS_CID);
-NS_DEFINE_NAMED_CID(NS_PAYMENT_REQUEST_SERVICE_CID);
-
-static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = {
-    {&kNS_GENERAL_RESPONSE_DATA_CID, false, nullptr,
-     GeneralResponseDataConstructor},
-    {&kNS_BASICCARD_RESPONSE_DATA_CID, false, nullptr,
-     BasicCardResponseDataConstructor},
-    {&kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID, false, nullptr,
-     PaymentCanMakeActionResponseConstructor},
-    {&kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID, false, nullptr,
-     PaymentAbortActionResponseConstructor},
-    {&kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID, false, nullptr,
-     PaymentShowActionResponseConstructor},
-    {&kNS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID, false, nullptr,
-     PaymentCompleteActionResponseConstructor},
-    {&kNS_GENERAL_CHANGE_DETAILS_CID, false, nullptr,
-     GeneralMethodChangeDetailsConstructor},
-    {&kNS_BASICCARD_CHANGE_DETAILS_CID, false, nullptr,
-     BasicCardMethodChangeDetailsConstructor},
-    {&kNS_PAYMENT_ADDRESS_CID, false, nullptr, PaymentAddressConstructor},
-    {&kNS_PAYMENT_REQUEST_SERVICE_CID, true, nullptr,
-     PaymentRequestServiceConstructor},
-    {nullptr}};
-
-static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = {
-    {NS_GENERAL_RESPONSE_DATA_CONTRACT_ID, &kNS_GENERAL_RESPONSE_DATA_CID},
-    {NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID, &kNS_BASICCARD_RESPONSE_DATA_CID},
-    {NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID,
-     &kNS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID},
-    {NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID,
-     &kNS_PAYMENT_ABORT_ACTION_RESPONSE_CID},
-    {NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID,
-     &kNS_PAYMENT_SHOW_ACTION_RESPONSE_CID},
-    {NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID,
-     &kNS_PAYMENT_COMPLETE_ACTION_RESPONSE_CID},
-    {NS_GENERAL_CHANGE_DETAILS_CONTRACT_ID, &kNS_GENERAL_CHANGE_DETAILS_CID},
-    {NS_BASICCARD_CHANGE_DETAILS_CONTRACT_ID,
-     &kNS_BASICCARD_CHANGE_DETAILS_CID},
-    {NS_PAYMENT_ADDRESS_CONTRACT_ID, &kNS_PAYMENT_ADDRESS_CID},
-    {NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID, &kNS_PAYMENT_REQUEST_SERVICE_CID},
-    {nullptr}};
-
-static const mozilla::Module::CategoryEntry kPaymentRequestCategories[] = {
-    {"payment-request", "GeneralResponseData",
-     NS_GENERAL_RESPONSE_DATA_CONTRACT_ID},
-    {"payment-request", "BasicCardResponseData",
-     NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID},
-    {"payment-request", "PaymentCanMakeActionResponse",
-     NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID},
-    {"payment-request", "PaymentAbortActionResponse",
-     NS_PAYMENT_ABORT_ACTION_RESPONSE_CONTRACT_ID},
-    {"payment-request", "PaymentShowActionResponse",
-     NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID},
-    {"payment-request", "PaymentCompleteActionResponse",
-     NS_PAYMENT_COMPLETE_ACTION_RESPONSE_CONTRACT_ID},
-    {"payment-request", "GeneralMethodChangeDetails",
-     NS_GENERAL_CHANGE_DETAILS_CONTRACT_ID},
-    {"payment-request", "BasicCardMethodChangeDetails",
-     NS_BASICCARD_CHANGE_DETAILS_CONTRACT_ID},
-    {"payment-request", "PaymentAddress", NS_PAYMENT_ADDRESS_CONTRACT_ID},
-    {"payment-request", "PaymentRequestService",
-     NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID},
-    {nullptr}};
-
-static const mozilla::Module kPaymentRequestModule = {
-    mozilla::Module::kVersion, kPaymentRequestCIDs, kPaymentRequestContracts,
-    kPaymentRequestCategories};
-
-NSMODULE_DEFN(PaymentRequestModule) = &kPaymentRequestModule;
new file mode 100644
--- /dev/null
+++ b/dom/payments/components.conf
@@ -0,0 +1,80 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{5296f79e-15ea-40c3-8196-19cfa64d328c}',
+        'contract_ids': ['@mozilla.org/dom/payments/basiccard-change-details;1'],
+        'type': 'mozilla::dom::BasicCardMethodChangeDetails',
+        'headers': ['/dom/payments/PaymentActionResponse.h'],
+        'categories': {'payment-request': 'BasicCardMethodChangeDetails'},
+    },
+    {
+        'cid': '{0d55a5e6-d185-44f0-b992-a8e1321e4bce}',
+        'contract_ids': ['@mozilla.org/dom/payments/basiccard-response-data;1'],
+        'type': 'mozilla::dom::BasicCardResponseData',
+        'headers': ['/dom/payments/PaymentActionResponse.h'],
+        'categories': {'payment-request': 'BasicCardResponseData'},
+    },
+    {
+        'cid': '{e031267e-bec8-4f3c-b0b1-396b77ca260c}',
+        'contract_ids': ['@mozilla.org/dom/payments/general-change-details;1'],
+        'type': 'mozilla::dom::GeneralMethodChangeDetails',
+        'headers': ['/dom/payments/PaymentActionResponse.h'],
+        'categories': {'payment-request': 'GeneralMethodChangeDetails'},
+    },
+    {
+        'cid': '{b986773e-2b30-4ed2-b8fe-6a96631c8000}',
+        'contract_ids': ['@mozilla.org/dom/payments/general-response-data;1'],
+        'type': 'mozilla::dom::GeneralResponseData',
+        'headers': ['/dom/payments/PaymentActionResponse.h'],
+        'categories': {'payment-request': 'GeneralResponseData'},
+    },
+    {
+        'cid': '{8c72bcdb-0c37-4786-a9e5-510afa2f8ede}',
+        'contract_ids': ['@mozilla.org/dom/payments/payment-abort-action-response;1'],
+        'type': 'mozilla::dom::PaymentAbortActionResponse',
+        'headers': ['/dom/payments/PaymentActionResponse.h'],
+        'categories': {'payment-request': 'PaymentAbortActionResponse'},
+    },
+    {
+        'cid': '{49a02241-7e48-477a-9345-9f246925dcb3}',
+        'contract_ids': ['@mozilla.org/dom/payments/payment-address;1'],
+        'type': 'mozilla::dom::payments::PaymentAddress',
+        'headers': ['PaymentRequestData.h'],
+        'categories': {'payment-request': 'PaymentAddress'},
+    },
+    {
+        'cid': '{52fc3f9f-c0cb-4874-b3d4-ee4b6e9cbe9c}',
+        'contract_ids': ['@mozilla.org/dom/payments/payment-canmake-action-response;1'],
+        'type': 'mozilla::dom::PaymentCanMakeActionResponse',
+        'headers': ['/dom/payments/PaymentActionResponse.h'],
+        'categories': {'payment-request': 'PaymentCanMakeActionResponse'},
+    },
+    {
+        'cid': '{62c01e69-9ca4-4060-99e4-b95f628c8e6d}',
+        'contract_ids': ['@mozilla.org/dom/payments/payment-complete-action-response;1'],
+        'type': 'mozilla::dom::PaymentCompleteActionResponse',
+        'headers': ['/dom/payments/PaymentActionResponse.h'],
+        'categories': {'payment-request': 'PaymentCompleteActionResponse'},
+    },
+    {
+        'cid': '{cccd665f-edf3-41fc-ab9b-fc55b37340aa}',
+        'contract_ids': ['@mozilla.org/dom/payments/payment-request-service;1'],
+        'singleton': True,
+        'type': 'mozilla::dom::PaymentRequestService',
+        'headers': ['PaymentRequestService.h'],
+        'constructor': 'mozilla::dom::PaymentRequestService::GetSingleton',
+        'categories': {'payment-request': 'PaymentRequestService'},
+    },
+    {
+        'cid': '{184385cb-2d35-4b99-a9a3-7c780bf66b9b}',
+        'contract_ids': ['@mozilla.org/dom/payments/payment-show-action-response;1'],
+        'type': 'mozilla::dom::PaymentShowActionResponse',
+        'headers': ['/dom/payments/PaymentActionResponse.h'],
+        'categories': {'payment-request': 'PaymentShowActionResponse'},
+    },
+]
--- a/dom/payments/moz.build
+++ b/dom/payments/moz.build
@@ -27,23 +27,26 @@ UNIFIED_SOURCES += [
     'BasicCardPayment.cpp',
     'MerchantValidationEvent.cpp',
     'PaymentActionResponse.cpp',
     'PaymentAddress.cpp',
     'PaymentMethodChangeEvent.cpp',
     'PaymentRequest.cpp',
     'PaymentRequestData.cpp',
     'PaymentRequestManager.cpp',
-    'PaymentRequestModule.cpp',
     'PaymentRequestService.cpp',
     'PaymentRequestUpdateEvent.cpp',
     'PaymentRequestUtils.cpp',
     'PaymentResponse.cpp',
 ]
 
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM: Web Payments")
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
rename from dom/presentation/PresentationDataChannelSessionTransport.js
rename to dom/presentation/PresentationDataChannelSessionTransport.jsm
--- a/dom/presentation/PresentationDataChannelSessionTransport.js
+++ b/dom/presentation/PresentationDataChannelSessionTransport.jsm
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 // Bug 1228209 - plan to remove this eventually
 function log(aMsg) {
   // dump("-*- PresentationDataChannelSessionTransport.js : " + aMsg + "\n");
 }
 
 const PRESENTATIONTRANSPORT_CID = Components.ID("{dd2bbf2f-3399-4389-8f5f-d382afb8b2d6}");
@@ -367,10 +366,9 @@ PresentationTransport.prototype = {
       });
       reader.readAsBinaryString(aData);
     } else {
       this._callback.notifyData(aData, false);
     }
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationTransportBuilder,
-                                                     PresentationTransport]);
+var EXPORTED_SYMBOLS = ["PresentationTransportBuilder", "PresentationTransport"];
deleted file mode 100644
--- a/dom/presentation/PresentationDataChannelSessionTransport.manifest
+++ /dev/null
@@ -1,6 +0,0 @@
-# PresentationDataChannelSessionTransport.js
-component {dd2bbf2f-3399-4389-8f5f-d382afb8b2d6} PresentationDataChannelSessionTransport.js
-contract @mozilla.org/presentation/datachanneltransport;1 {dd2bbf2f-3399-4389-8f5f-d382afb8b2d6}
-
-component {215b2f62-46e2-4004-a3d1-6858e56c20f3} PresentationDataChannelSessionTransport.js
-contract @mozilla.org/presentation/datachanneltransportbuilder;1 {215b2f62-46e2-4004-a3d1-6858e56c20f3}
rename from dom/presentation/PresentationNetworkHelper.js
rename to dom/presentation/PresentationNetworkHelper.jsm
--- a/dom/presentation/PresentationNetworkHelper.js
+++ b/dom/presentation/PresentationNetworkHelper.jsm
@@ -1,26 +1,22 @@
 // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {EventDispatcher} = ChromeUtils.import("resource://gre/modules/Messaging.jsm");
-const {XPCOMUtils} = 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: ChromeUtils.generateQI([Ci.nsIPresentationNetworkHelper]),
 
   getWifiIPAddress(aListener) {
     EventDispatcher.instance.sendRequestForResult({type: "Wifi:GetIPAddress"})
              .then(result => aListener.onGetWifiIPAddress(result),
                    err => aListener.onError(err));
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationNetworkHelper]);
+var EXPORTED_SYMBOLS = ["PresentationNetworkHelper"];
deleted file mode 100644
--- a/dom/presentation/PresentationNetworkHelper.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-# PresentationNetworkHelper.js
-component {5fb96caa-6d49-4f6b-9a4b-65dd0d51f92d} PresentationNetworkHelper.js
-contract @mozilla.org/presentation-device/networkHelper;1 {5fb96caa-6d49-4f6b-9a4b-65dd0d51f92d}
new file mode 100644
--- /dev/null
+++ b/dom/presentation/components.conf
@@ -0,0 +1,30 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{dd2bbf2f-3399-4389-8f5f-d382afb8b2d6}',
+        'contract_ids': ['@mozilla.org/presentation/datachanneltransport;1'],
+        'jsm': 'resource://gre/modules/PresentationDataChannelSessionTransport.jsm',
+        'constructor': 'PresentationTransport',
+    },
+    {
+        'cid': '{215b2f62-46e2-4004-a3d1-6858e56c20f3}',
+        'contract_ids': ['@mozilla.org/presentation/datachanneltransportbuilder;1'],
+        'jsm': 'resource://gre/modules/PresentationDataChannelSessionTransport.jsm',
+        'constructor': 'PresentationTransportBuilder',
+    },
+]
+
+if buildconfig.substs['MOZ_WIDGET_TOOLKIT'] == 'android':
+    Classes += [
+        {
+            'cid': '{5fb96caa-6d49-4f6b-9a4b-65dd0d51f92d}',
+            'contract_ids': ['@mozilla.org/presentation-device/networkHelper;1'],
+            'jsm': 'resource://gre/modules/PresentationNetworkHelper.jsm',
+            'constructor': 'PresentationNetworkHelper',
+        },
+    ]
--- a/dom/presentation/moz.build
+++ b/dom/presentation/moz.build
@@ -55,25 +55,27 @@ UNIFIED_SOURCES += [
     'PresentationService.cpp',
     'PresentationSessionInfo.cpp',
     'PresentationSessionRequest.cpp',
     'PresentationTCPSessionTransport.cpp',
     'PresentationTerminateRequest.cpp',
     'PresentationTransportBuilderConstructor.cpp'
 ]
 
-EXTRA_COMPONENTS += [
-    'PresentationDataChannelSessionTransport.js',
-    'PresentationDataChannelSessionTransport.manifest',
+EXTRA_JS_MODULES += [
+    'PresentationDataChannelSessionTransport.jsm',
+]
+
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
-    EXTRA_COMPONENTS += [
-        'PresentationNetworkHelper.js',
-        'PresentationNetworkHelper.manifest',
+    EXTRA_JS_MODULES += [
+        'PresentationNetworkHelper.jsm',
     ]
 
 IPDL_SOURCES += [
     'ipc/PPresentation.ipdl',
     'ipc/PPresentationBuilder.ipdl',
     'ipc/PPresentationRequest.ipdl'
 ]
 
rename from dom/presentation/provider/AndroidCastDeviceProvider.js
rename to dom/presentation/provider/AndroidCastDeviceProvider.jsm
--- a/dom/presentation/provider/AndroidCastDeviceProvider.js
+++ b/dom/presentation/provider/AndroidCastDeviceProvider.jsm
@@ -1,16 +1,15 @@
 /* -*- 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/. */
 "use strict";
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const {EventDispatcher} = ChromeUtils.import("resource://gre/modules/Messaging.jsm");
 
 function log(str) {
   // dump("-*- AndroidCastDeviceProvider -*-: " + str + "\n");
 }
 
 // Helper function: transfer nsIPresentationChannelDescription to json
@@ -455,9 +454,9 @@ AndroidCastDeviceProvider.prototype = {
     }
   },
 
   classID: Components.ID("{7394f24c-dbc3-48c8-8a47-cd10169b7c6b}"),
   QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
                                           Ci.nsIPresentationDeviceProvider]),
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AndroidCastDeviceProvider]);
+var EXPORTED_SYMBOLS = ["AndroidCastDeviceProvider"];
deleted file mode 100644
--- a/dom/presentation/provider/AndroidCastDeviceProvider.manifest
+++ /dev/null
@@ -1,4 +0,0 @@
-# AndroidCastDeviceProvider.js
-component {7394f24c-dbc3-48c8-8a47-cd10169b7c6b} AndroidCastDeviceProvider.js
-contract @mozilla.org/presentation-device/android-cast-device-provider;1 {7394f24c-dbc3-48c8-8a47-cd10169b7c6b}
-category presentation-device-provider AndroidCastDeviceProvider @mozilla.org/presentation-device/android-cast-device-provider;1
deleted file mode 100644
--- a/dom/presentation/provider/BuiltinProviders.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {f4079b8b-ede5-4b90-a112-5b415a931deb} PresentationControlService.js
-contract @mozilla.org/presentation/control-service;1 {f4079b8b-ede5-4b90-a112-5b415a931deb}
rename from dom/presentation/provider/PresentationControlService.js
rename to dom/presentation/provider/PresentationControlService.jsm
--- a/dom/presentation/provider/PresentationControlService.js
+++ b/dom/presentation/provider/PresentationControlService.jsm
@@ -1,14 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
 const {clearTimeout, setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
 
 ChromeUtils.defineModuleGetter(this, "ControllerStateMachine",
                                "resource://gre/modules/presentation/ControllerStateMachine.jsm");
 ChromeUtils.defineModuleGetter(this, "ReceiverStateMachine",
                                "resource://gre/modules/presentation/ReceiverStateMachine.jsm");
@@ -942,9 +941,9 @@ TCPControlChannel.prototype = {
     this._listener.onIceCandidate(candidate);
   },
 
   classID: Components.ID("{fefb8286-0bdc-488b-98bf-0c11b485c955}"),
   QueryInterface: ChromeUtils.generateQI([Ci.nsIPresentationControlChannel,
                                           Ci.nsIStreamListener]),
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationControlService]); // jshint ignore:line
+var EXPORTED_SYMBOLS = ["PresentationControlService"];
new file mode 100644
--- /dev/null
+++ b/dom/presentation/provider/components.conf
@@ -0,0 +1,25 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{f4079b8b-ede5-4b90-a112-5b415a931deb}',
+        'contract_ids': ['@mozilla.org/presentation/control-service;1'],
+        'jsm': 'resource://gre/modules/PresentationControlService.jsm',
+        'constructor': 'PresentationControlService',
+    },
+]
+
+if buildconfig.substs['MOZ_WIDGET_TOOLKIT'] == 'android':
+    Classes += [
+        {
+            'cid': '{7394f24c-dbc3-48c8-8a47-cd10169b7c6b}',
+            'contract_ids': ['@mozilla.org/presentation-device/android-cast-device-provider;1'],
+            'jsm': 'resource://gre/modules/AndroidCastDeviceProvider.jsm',
+            'constructor': 'AndroidCastDeviceProvider',
+            'categories': {'presentation-device-provider': 'AndroidCastDeviceProvider'},
+        },
+    ]
--- a/dom/presentation/provider/moz.build
+++ b/dom/presentation/provider/moz.build
@@ -1,32 +1,34 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-EXTRA_COMPONENTS += [
-    'BuiltinProviders.manifest',
-    'PresentationControlService.js'
+EXTRA_JS_MODULES += [
+    'PresentationControlService.jsm'
 ]
 
 UNIFIED_SOURCES += [
     'DeviceProviderHelpers.cpp',
     'MulticastDNSDeviceProvider.cpp',
     'PresentationDeviceProviderModule.cpp',
 ]
 
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
+
 EXTRA_JS_MODULES.presentation += [
     'ControllerStateMachine.jsm',
     'ReceiverStateMachine.jsm',
     'StateMachineHelper.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
-    EXTRA_COMPONENTS += [
+    EXTRA_JS_MODULES += [
         # For android presentation device
-        'AndroidCastDeviceProvider.js',
-        'AndroidCastDeviceProvider.manifest',
+        'AndroidCastDeviceProvider.jsm',
     ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 FINAL_LIBRARY = 'xul'
--- a/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js
@@ -180,34 +180,31 @@ function loadPrivilegedScriptTest() {
     if (!registrar.isCIDRegistered(mockedClassId)) {
       try {
         originalClassId = registrar.contractIDToCID(contractId);
         originalFactory = Cm.getClassObject(Cc[contractId], Ci.nsIFactory);
       } catch (ex) {
         originalClassId = "";
         originalFactory = null;
       }
-      if (originalFactory) {
-        registrar.unregisterFactory(originalClassId, originalFactory);
-      }
       registrar.registerFactory(mockedClassId, "", contractId, mockedFactory);
     }
 
     return { contractId,
              mockedClassId,
              mockedFactory,
              originalClassId,
              originalFactory };
   }
 
   function registerOriginalFactory(contractId, mockedClassId, mockedFactory, originalClassId, originalFactory) {
     if (originalFactory) {
       var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
       registrar.unregisterFactory(mockedClassId, mockedFactory);
-      registrar.registerFactory(originalClassId, "", contractId, originalFactory);
+      registrar.registerFactory(originalClassId, "", contractId, null);
     }
   }
 
   /* Register mocked factories. */
   const originalFactoryData = [];
   const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
                         .getService(Ci.nsIUUIDGenerator);
   originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/datachanneltransportbuilder;1",
--- a/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js
+++ b/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js
@@ -95,17 +95,17 @@ ContractHook.prototype = {
   reset() {},
 
   cleanup() {
     this.reset();
 
     this.unregister();
     let prevContract = this.hookedMap.get(this._contractID).pop();
 
-    if (prevContract.factory) {
+    if (prevContract.classID) {
       registrar.registerFactory(prevContract.classID,
                                 "",
                                 this._contractID,
                                 prevContract.factory);
     }
   },
 
   unregister() {
@@ -115,17 +115,21 @@ ContractHook.prototype = {
       classID = registrar.contractIDToCID(this._contractID);
       factory = Cm.getClassObject(Cc[this._contractID], Ci.nsIFactory);
     } catch (ex) {
       classID = "";
       factory = null;
     }
 
     if (factory) {
-      registrar.unregisterFactory(classID, factory);
+      try {
+        registrar.unregisterFactory(classID, factory);
+      } catch (e) {
+        factory = null;
+      }
     }
 
     return { classID, factory };
   },
 };
 
 function MockDNSServiceInfo() {}
 MockDNSServiceInfo.prototype = {
rename from dom/push/Push.js
rename to dom/push/Push.jsm
--- a/dom/push/Push.js
+++ b/dom/push/Push.jsm
@@ -280,9 +280,9 @@ PushSubscriptionCallback.prototype = {
           "Error retrieving push subscription.",
           "AbortError"
         );
     }
     this.reject(error);
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);
+var EXPORTED_SYMBOLS = ["Push"];
--- a/dom/push/Push.manifest
+++ b/dom/push/Push.manifest
@@ -1,11 +1,4 @@
-# DOM API
-component {cde1d019-fad8-4044-b141-65fb4fb7a245} Push.js
-contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
-
-# XPCOM components.
-component {daaa8d73-677e-4233-8acd-2c404bd01658} PushComponents.js
-contract @mozilla.org/push/Service;1 {daaa8d73-677e-4233-8acd-2c404bd01658}
 category app-startup PushServiceParent @mozilla.org/push/Service;1 process=main
 
 # For immediate loading of PushService instead of delayed loading.
 category android-push-service PushServiceParent @mozilla.org/push/Service;1 process=main
rename from dom/push/PushComponents.js
rename to dom/push/PushComponents.jsm
--- a/dom/push/PushComponents.js
+++ b/dom/push/PushComponents.jsm
@@ -108,28 +108,32 @@ PushServiceBase.prototype = {
   },
 };
 
 /**
  * The parent process implementation of `nsIPushService`. This version loads
  * `PushService.jsm` at startup and calls its methods directly. It also
  * receives and responds to requests from the content process.
  */
+let parentInstance;
 function PushServiceParent() {
+  if (parentInstance) {
+    return parentInstance;
+  }
+  parentInstance = this;
+
   PushServiceBase.call(this);
 }
 
 PushServiceParent.prototype = Object.create(PushServiceBase.prototype);
 
 XPCOMUtils.defineLazyServiceGetter(PushServiceParent.prototype, "_mm",
   "@mozilla.org/parentprocessmessagemanager;1", "nsISupports");
 
 Object.assign(PushServiceParent.prototype, {
-  _xpcom_factory: XPCOMUtils.generateSingletonFactory(PushServiceParent),
-
   _messages: [
     "Push:Register",
     "Push:Registration",
     "Push:Unregister",
     "Push:Clear",
     "Push:NotificationForOriginShown",
     "Push:NotificationForOriginClosed",
     "Push:ReportError",
@@ -301,37 +305,41 @@ Object.defineProperty(PushServiceParent.
   get() {
     return this._service || PushService;
   },
   set(impl) {
     this._service = impl;
   },
 });
 
+let contentInstance;
 /**
  * The content process implementation of `nsIPushService`. This version
  * uses the child message manager to forward calls to the parent process.
  * The parent Push service instance handles the request, and responds with a
  * message containing the result.
  */
 function PushServiceContent() {
+  if (contentInstance) {
+    return contentInstance;
+  }
+  contentInstance = this;
+
   PushServiceBase.apply(this, arguments);
   this._requests = new Map();
   this._requestId = 0;
 }
 
 PushServiceContent.prototype = Object.create(PushServiceBase.prototype);
 
 XPCOMUtils.defineLazyServiceGetter(PushServiceContent.prototype,
   "_mm", "@mozilla.org/childprocessmessagemanager;1",
   "nsISupports");
 
 Object.assign(PushServiceContent.prototype, {
-  _xpcom_factory: XPCOMUtils.generateSingletonFactory(PushServiceContent),
-
   _messages: [
     "PushService:Register:OK",
     "PushService:Register:KO",
     "PushService:Registration:OK",
     "PushService:Registration:KO",
     "PushService:Unregister:OK",
     "PushService:Unregister:KO",
     "PushService:Clear:OK",
@@ -543,13 +551,13 @@ PushSubscription.prototype = {
     let rawKey = new Uint8Array(key);
     if (outKeyLen) {
       outKeyLen.value = rawKey.length;
     }
     return rawKey;
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
-  // Export the correct implementation depending on whether we're running in
-  // the parent or content process.
-  isParent ? PushServiceParent : PushServiceContent,
-]);
+// Export the correct implementation depending on whether we're running in
+// the parent or content process.
+let Service = isParent ? PushServiceParent : PushServiceContent;
+
+var EXPORTED_SYMBOLS = ["Service"];
new file mode 100644
--- /dev/null
+++ b/dom/push/components.conf
@@ -0,0 +1,20 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Classes = [
+    {
+        'cid': '{cde1d019-fad8-4044-b141-65fb4fb7a245}',
+        'contract_ids': ['@mozilla.org/push/PushManager;1'],
+        'jsm': 'resource://gre/modules/Push.jsm',
+        'constructor': 'Push',
+    },
+    {
+        'cid': '{daaa8d73-677e-4233-8acd-2c404bd01658}',
+        'contract_ids': ['@mozilla.org/push/Service;1'],
+        'jsm': 'resource://gre/modules/PushComponents.jsm',
+        'constructor': 'Service',
+    },
+]
--- a/dom/push/moz.build
+++ b/dom/push/moz.build
@@ -2,23 +2,23 @@
 # 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/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM: Push Notifications")
 
 EXTRA_COMPONENTS += [
-    'Push.js',
     'Push.manifest',
-    'PushComponents.js',
 ]
 
 EXTRA_JS_MODULES += [
+    'Push.jsm',
     'PushBroadcastService.jsm',
+    'PushComponents.jsm',
     'PushCrypto.jsm',
     'PushDB.jsm',
     'PushRecord.jsm',
     'PushService.jsm',
 ]
 
 if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
     # Everything but Fennec.
@@ -27,16 +27,20 @@ if CONFIG['MOZ_BUILD_APP'] != 'mobile/an
         'PushServiceWebSocket.jsm',
     ]
 else:
     # Fennec only.
     EXTRA_JS_MODULES += [
         'PushServiceAndroidGCM.jsm',
     ]
 
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
+
 MOCHITEST_MANIFESTS += [
     'test/mochitest.ini',
 ]
 
 XPCSHELL_TESTS_MANIFESTS += [
     'test/xpcshell/xpcshell.ini',
 ]
 
--- a/dom/svg/DOMSVGAngle.cpp
+++ b/dom/svg/DOMSVGAngle.cpp
@@ -1,47 +1,49 @@
 /* -*- 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/. */
 
 #include "DOMSVGAngle.h"
-#include "SVGAngle.h"
+#include "SVGOrient.h"
 #include "mozilla/dom/SVGAngleBinding.h"
 #include "mozilla/dom/SVGSVGElement.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGAngle, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGAngle, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGAngle, Release)
 
 DOMSVGAngle::DOMSVGAngle(SVGSVGElement* aSVGElement)
     : mSVGElement(aSVGElement), mType(DOMSVGAngle::CreatedValue) {
-  mVal = new SVGAngle();
+  mVal = new SVGOrient();
   mVal->Init();
 }
 
 JSObject* DOMSVGAngle::WrapObject(JSContext* aCx,
                                   JS::Handle<JSObject*> aGivenProto) {
   return SVGAngle_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 uint16_t DOMSVGAngle::UnitType() const {
   if (mType == AnimValue) {
+    mSVGElement->FlushAnimations();
     return mVal->mAnimValUnit;
   }
   return mVal->mBaseValUnit;
 }
 
 float DOMSVGAngle::Value() const {
   if (mType == AnimValue) {
+    mSVGElement->FlushAnimations();
     return mVal->GetAnimValue();
   }
   return mVal->GetBaseValue();
 }
 
 void DOMSVGAngle::SetValue(float aValue, ErrorResult& rv) {
   if (mType == AnimValue) {
     rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
@@ -98,13 +100,14 @@ void DOMSVGAngle::SetValueAsString(const
   }
   bool isBaseVal = mType == BaseValue;
   rv = mVal->SetBaseValueString(aValue, isBaseVal ? mSVGElement.get() : nullptr,
                                 isBaseVal);
 }
 
 void DOMSVGAngle::GetValueAsString(nsAString& aValue) {
   if (mType == AnimValue) {
-    mVal->GetAnimValueString(aValue);
+    mSVGElement->FlushAnimations();
+    mVal->GetAnimAngleValueString(aValue);
   } else {
-    mVal->GetBaseValueString(aValue);
+    mVal->GetBaseAngleValueString(aValue);
   }
 }
--- a/dom/svg/DOMSVGAngle.h
+++ b/dom/svg/DOMSVGAngle.h
@@ -6,33 +6,34 @@
 
 #ifndef mozilla_dom_SVGAngle_h
 #define mozilla_dom_SVGAngle_h
 
 #include "nsWrapperCache.h"
 #include "SVGElement.h"
 #include "mozilla/Attributes.h"
 
-class SVGAngle;
+namespace mozilla {
 
-namespace mozilla {
+class SVGOrient;
+
 namespace dom {
 class SVGSVGElement;
 
 class DOMSVGAngle final : public nsWrapperCache {
  public:
   typedef enum { BaseValue, AnimValue, CreatedValue } AngleType;
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMSVGAngle)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMSVGAngle)
 
   /**
    * Generic ctor for DOMSVGAngle objects that are created for an attribute.
    */
-  DOMSVGAngle(SVGAngle* aVal, SVGElement* aSVGElement, AngleType aType)
+  DOMSVGAngle(SVGOrient* aVal, SVGElement* aSVGElement, AngleType aType)
       : mVal(aVal), mSVGElement(aSVGElement), mType(aType) {}
 
   /**
    * Ctor for creating the objects returned by SVGSVGElement.createSVGAngle(),
    * which do not initially belong to an attribute.
    */
   explicit DOMSVGAngle(SVGSVGElement* aSVGElement);
 
@@ -48,18 +49,18 @@ class DOMSVGAngle final : public nsWrapp
   void SetValueInSpecifiedUnits(float aValue, ErrorResult& rv);
   void SetValueAsString(const nsAString& aValue, ErrorResult& rv);
   void NewValueSpecifiedUnits(uint16_t unitType, float value, ErrorResult& rv);
   void ConvertToSpecifiedUnits(uint16_t unitType, ErrorResult& rv);
 
  protected:
   ~DOMSVGAngle();
 
-  SVGAngle* mVal;  // if mType is CreatedValue, we own the angle.  Otherwise,
-                   // the element does.
+  SVGOrient* mVal;  // if mType is CreatedValue, we own the angle.  Otherwise,
+                    // the element does.
   RefPtr<SVGElement> mSVGElement;
   AngleType mType;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_SVGAngle_h
--- a/dom/svg/SVGAnimatedAngle.cpp
+++ b/dom/svg/SVGAnimatedAngle.cpp
@@ -1,16 +1,16 @@
 /* -*- 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/. */
 
 #include "SVGAnimatedAngle.h"
-#include "SVGAngle.h"
+#include "SVGOrient.h"
 #include "mozilla/dom/SVGAnimatedAngleBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedAngle, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SVGAnimatedAngle, AddRef)
--- a/dom/svg/SVGAnimatedAngle.h
+++ b/dom/svg/SVGAnimatedAngle.h
@@ -6,41 +6,42 @@
 
 #ifndef mozilla_dom_SVGAnimatedAngle_h
 #define mozilla_dom_SVGAnimatedAngle_h
 
 #include "nsWrapperCache.h"
 #include "SVGElement.h"
 #include "mozilla/Attributes.h"
 
-class SVGAngle;
+namespace mozilla {
 
-namespace mozilla {
+class SVGOrient;
+
 namespace dom {
 
 class DOMSVGAngle;
 
 class SVGAnimatedAngle final : public nsWrapperCache {
  public:
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SVGAnimatedAngle)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(SVGAnimatedAngle)
 
-  SVGAnimatedAngle(SVGAngle* aVal, SVGElement* aSVGElement)
+  SVGAnimatedAngle(SVGOrient* aVal, SVGElement* aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
 
   // WebIDL
   SVGElement* GetParentObject() { return mSVGElement; }
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
   already_AddRefed<DOMSVGAngle> BaseVal();
   already_AddRefed<DOMSVGAngle> AnimVal();
 
  protected:
   ~SVGAnimatedAngle();
 
-  SVGAngle* mVal;  // kept alive because it belongs to content
+  SVGOrient* mVal;  // kept alive because it belongs to content
   RefPtr<SVGElement> mSVGElement;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_SVGAnimatedAngle_h
--- a/dom/svg/SVGAttrValueWrapper.cpp
+++ b/dom/svg/SVGAttrValueWrapper.cpp
@@ -2,33 +2,33 @@
 /* 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/. */
 
 #include "SVGAttrValueWrapper.h"
 
 #include "SVGAnimatedPreserveAspectRatio.h"
-#include "SVGAngle.h"
 #include "SVGIntegerPair.h"
 #include "nsSVGLength2.h"
 #include "SVGLengthList.h"
 #include "SVGNumberPair.h"
 #include "SVGNumberList.h"
+#include "SVGOrient.h"
 #include "SVGPathData.h"
 #include "SVGPointList.h"
 #include "SVGStringList.h"
 #include "SVGTransformList.h"
 #include "SVGViewBox.h"
 
 namespace mozilla {
 
-/*static*/ void SVGAttrValueWrapper::ToString(const SVGAngle* aAngle,
+/*static*/ void SVGAttrValueWrapper::ToString(const SVGOrient* aOrient,
                                               nsAString& aResult) {
-  aAngle->GetBaseValueString(aResult);
+  aOrient->GetBaseValueString(aResult);
 }
 
 /*static*/ void SVGAttrValueWrapper::ToString(
     const SVGIntegerPair* aIntegerPair, nsAString& aResult) {
   aIntegerPair->GetBaseValueString(aResult);
 }
 
 /*static*/ void SVGAttrValueWrapper::ToString(const nsSVGLength2* aLength,
--- a/dom/svg/SVGAttrValueWrapper.h
+++ b/dom/svg/SVGAttrValueWrapper.h
@@ -12,31 +12,31 @@
  * types don't need to be exported outside the SVG module.
  */
 
 #include "nsString.h"
 
 class nsSVGLength2;
 
 namespace mozilla {
-class SVGAngle;
 class SVGIntegerPair;
 class SVGLengthList;
 class SVGNumberList;
 class SVGNumberPair;
+class SVGOrient;
 class SVGPathData;
 class SVGPointList;
 class SVGAnimatedPreserveAspectRatio;
 class SVGStringList;
 class SVGTransformList;
 class SVGViewBox;
 
 class SVGAttrValueWrapper {
  public:
-  static void ToString(const SVGAngle* aAngle, nsAString& aResult);
+  static void ToString(const SVGOrient* aAngle, nsAString& aResult);
   static void ToString(const SVGIntegerPair* aIntegerPair, nsAString& aResult);
   static void ToString(const nsSVGLength2* aLength, nsAString& aResult);
   static void ToString(const SVGLengthList* aLengthList, nsAString& aResult);
   static void ToString(const SVGNumberList* aNumberList, nsAString& aResult);
   static void ToString(const SVGNumberPair* aNumberPair, nsAString& aResult);
   static void ToString(const SVGPathData* aPathData, nsAString& aResult);
   static void ToString(const SVGPointList* aPointList, nsAString& aResult);
   static void ToString(
--- a/dom/svg/SVGElement.cpp
+++ b/dom/svg/SVGElement.cpp
@@ -33,30 +33,30 @@
 #include "nsIContentInlines.h"
 #include "mozilla/dom/Document.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIPresShell.h"
 #include "nsIFrame.h"
 #include "nsQueryObject.h"
 #include "nsLayoutUtils.h"
-#include "SVGAngle.h"
 #include "SVGAnimatedNumberList.h"
 #include "SVGAnimatedLengthList.h"
 #include "SVGAnimatedPointList.h"
 #include "SVGAnimatedPathSegList.h"
 #include "SVGAnimatedTransformList.h"
 #include "SVGBoolean.h"
 #include "SVGEnum.h"
 #include "SVGInteger.h"
 #include "SVGIntegerPair.h"
 #include "nsSVGLength2.h"
 #include "SVGMotionSMILAttr.h"
 #include "nsSVGNumber2.h"
 #include "SVGNumberPair.h"
+#include "SVGOrient.h"
 #include "SVGString.h"
 #include "SVGViewBox.h"
 #include <stdarg.h>
 
 // This is needed to ensure correct handling of calls to the
 // vararg-list methods in this file:
 //   SVGElement::GetAnimated{Length,Number,Integer}Values
 // See bug 547964 for details:
@@ -155,34 +155,34 @@ nsresult SVGElement::Init() {
   }
 
   IntegerPairAttributesInfo integerPairInfo = GetIntegerPairInfo();
 
   for (i = 0; i < integerPairInfo.mIntegerPairCount; i++) {
     integerPairInfo.Reset(i);
   }
 
-  AngleAttributesInfo angleInfo = GetAngleInfo();
-
-  for (i = 0; i < angleInfo.mAngleCount; i++) {
-    angleInfo.Reset(i);
-  }
-
   BooleanAttributesInfo booleanInfo = GetBooleanInfo();
 
   for (i = 0; i < booleanInfo.mBooleanCount; i++) {
     booleanInfo.Reset(i);
   }
 
   EnumAttributesInfo enumInfo = GetEnumInfo();
 
   for (i = 0; i < enumInfo.mEnumCount; i++) {
     enumInfo.Reset(i);
   }
 
+  SVGOrient* orient = GetOrient();
+
+  if (orient) {
+    orient->Init();
+  }
+
   SVGViewBox* viewBox = GetViewBox();
 
   if (viewBox) {
     viewBox->Init();
   }
 
   SVGAnimatedPreserveAspectRatio* preserveAspectRatio =
       GetPreserveAspectRatio();
@@ -457,34 +457,16 @@ bool SVGElement::ParseAttribute(int32_t 
           }
           foundMatch = true;
           break;
         }
       }
     }
 
     if (!foundMatch) {
-      // Check for SVGAngle attribute
-      AngleAttributesInfo angleInfo = GetAngleInfo();
-      for (i = 0; i < angleInfo.mAngleCount; i++) {
-        if (aAttribute == angleInfo.mAngleInfo[i].mName) {
-          rv = angleInfo.mAngles[i].SetBaseValueString(aValue, this, false);
-          if (NS_FAILED(rv)) {
-            angleInfo.Reset(i);
-          } else {
-            aResult.SetTo(angleInfo.mAngles[i], &aValue);
-            didSetResult = true;
-          }
-          foundMatch = true;
-          break;
-        }
-      }
-    }
-
-    if (!foundMatch) {
       // Check for SVGBoolean attribute
       BooleanAttributesInfo booleanInfo = GetBooleanInfo();
       for (i = 0; i < booleanInfo.mBooleanCount; i++) {
         if (aAttribute == booleanInfo.mBooleanInfo[i].mName) {
           nsAtom* valAtom = NS_GetStaticAtom(aValue);
           rv = valAtom
                    ? booleanInfo.mBooleans[i].SetBaseValueAtom(valAtom, this)
                    : NS_ERROR_DOM_SYNTAX_ERR;
@@ -542,18 +524,31 @@ bool SVGElement::ParseAttribute(int32_t 
           }
           foundMatch = true;
           break;
         }
       }
     }
 
     if (!foundMatch) {
-      // Check for SVGViewBox attribute
-      if (aAttribute == nsGkAtoms::viewBox) {
+      // Check for orient attribute
+      if (aAttribute == nsGkAtoms::orient) {
+        SVGOrient* orient = GetOrient();
+        if (orient) {
+          rv = orient->SetBaseValueString(aValue, this, false);
+          if (NS_FAILED(rv)) {
+            orient->Init();
+          } else {
+            aResult.SetTo(*orient, &aValue);
+            didSetResult = true;
+          }
+          foundMatch = true;
+        }
+        // Check for SVGViewBox attribute
+      } else if (aAttribute == nsGkAtoms::viewBox) {
         SVGViewBox* viewBox = GetViewBox();
         if (viewBox) {
           rv = viewBox->SetBaseValueString(aValue, this, false);
           if (NS_FAILED(rv)) {
             viewBox->Init();
           } else {
             aResult.SetTo(*viewBox, &aValue);
             didSetResult = true;
@@ -745,27 +740,16 @@ void SVGElement::UnsetAttrInternal(int32
     for (uint32_t i = 0; i < intPairInfo.mIntegerPairCount; i++) {
       if (aName == intPairInfo.mIntegerPairInfo[i].mName) {
         MaybeSerializeAttrBeforeRemoval(aName, aNotify);
         intPairInfo.Reset(i);
         return;
       }
     }
 
-    // Check if this is an angle attribute going away
-    AngleAttributesInfo angleInfo = GetAngleInfo();
-
-    for (uint32_t i = 0; i < angleInfo.mAngleCount; i++) {
-      if (aName == angleInfo.mAngleInfo[i].mName) {
-        MaybeSerializeAttrBeforeRemoval(aName, aNotify);
-        angleInfo.Reset(i);
-        return;
-      }
-    }
-
     // Check if this is a boolean attribute going away
     BooleanAttributesInfo boolInfo = GetBooleanInfo();
 
     for (uint32_t i = 0; i < boolInfo.mBooleanCount; i++) {
       if (aName == boolInfo.mBooleanInfo[i].mName) {
         boolInfo.Reset(i);
         return;
       }
@@ -776,17 +760,27 @@ void SVGElement::UnsetAttrInternal(int32
 
     for (uint32_t i = 0; i < enumInfo.mEnumCount; i++) {
       if (aName == enumInfo.mEnumInfo[i].mName) {
         enumInfo.Reset(i);
         return;
       }
     }
 
-    // Check if this is a nsViewBox attribute going away
+    // Check if this is an orient attribute going away
+    if (aName == nsGkAtoms::orient) {
+      SVGOrient* orient = GetOrient();
+      if (orient) {
+        MaybeSerializeAttrBeforeRemoval(aName, aNotify);
+        orient->Init();
+        return;
+      }
+    }
+
+    // Check if this is a viewBox attribute going away
     if (aName == nsGkAtoms::viewBox) {
       SVGViewBox* viewBox = GetViewBox();
       if (viewBox) {
         MaybeSerializeAttrBeforeRemoval(aName, aNotify);
         viewBox->Init();
         return;
       }
     }
@@ -1810,53 +1804,16 @@ void SVGElement::DidAnimateIntegerPair(u
   if (frame) {
     IntegerPairAttributesInfo info = GetIntegerPairInfo();
     frame->AttributeChanged(kNameSpaceID_None,
                             info.mIntegerPairInfo[aAttrEnum].mName,
                             MutationEvent_Binding::SMIL);
   }
 }
 
-SVGElement::AngleAttributesInfo SVGElement::GetAngleInfo() {
-  return AngleAttributesInfo(nullptr, nullptr, 0);
-}
-
-void SVGElement::AngleAttributesInfo::Reset(uint8_t aAttrEnum) {
-  mAngles[aAttrEnum].Init(aAttrEnum, mAngleInfo[aAttrEnum].mDefaultValue,
-                          mAngleInfo[aAttrEnum].mDefaultUnitType);
-}
-
-nsAttrValue SVGElement::WillChangeAngle(uint8_t aAttrEnum) {
-  return WillChangeValue(GetAngleInfo().mAngleInfo[aAttrEnum].mName);
-}
-
-void SVGElement::DidChangeAngle(uint8_t aAttrEnum,
-                                const nsAttrValue& aEmptyOrOldValue) {
-  AngleAttributesInfo info = GetAngleInfo();
-
-  NS_ASSERTION(info.mAngleCount > 0,
-               "DidChangeAngle on element with no angle attribs");
-  NS_ASSERTION(aAttrEnum < info.mAngleCount, "aAttrEnum out of range");
-
-  nsAttrValue newValue;
-  newValue.SetTo(info.mAngles[aAttrEnum], nullptr);
-
-  DidChangeValue(info.mAngleInfo[aAttrEnum].mName, aEmptyOrOldValue, newValue);
-}
-
-void SVGElement::DidAnimateAngle(uint8_t aAttrEnum) {
-  nsIFrame* frame = GetPrimaryFrame();
-
-  if (frame) {
-    AngleAttributesInfo info = GetAngleInfo();
-    frame->AttributeChanged(kNameSpaceID_None, info.mAngleInfo[aAttrEnum].mName,
-                            MutationEvent_Binding::SMIL);
-  }
-}
-
 SVGElement::BooleanAttributesInfo SVGElement::GetBooleanInfo() {
   return BooleanAttributesInfo(nullptr, nullptr, 0);
 }
 
 void SVGElement::BooleanAttributesInfo::Reset(uint8_t aAttrEnum) {
   mBooleans[aAttrEnum].Init(aAttrEnum, mBooleanInfo[aAttrEnum].mDefaultValue);
 }
 
@@ -1913,16 +1870,42 @@ void SVGElement::DidAnimateEnum(uint8_t 
 
   if (frame) {
     EnumAttributesInfo info = GetEnumInfo();
     frame->AttributeChanged(kNameSpaceID_None, info.mEnumInfo[aAttrEnum].mName,
                             MutationEvent_Binding::SMIL);
   }
 }
 
+SVGOrient* SVGElement::GetOrient() { return nullptr; }
+
+nsAttrValue SVGElement::WillChangeOrient() {
+  return WillChangeValue(nsGkAtoms::orient);
+}
+
+void SVGElement::DidChangeOrient(const nsAttrValue& aEmptyOrOldValue) {
+  SVGOrient* orient = GetOrient();
+
+  NS_ASSERTION(orient, "DidChangeOrient on element with no orient attrib");
+
+  nsAttrValue newValue;
+  newValue.SetTo(*orient, nullptr);
+
+  DidChangeValue(nsGkAtoms::orient, aEmptyOrOldValue, newValue);
+}
+
+void SVGElement::DidAnimateOrient() {
+  nsIFrame* frame = GetPrimaryFrame();
+
+  if (frame) {
+    frame->AttributeChanged(kNameSpaceID_None, nsGkAtoms::orient,
+                            MutationEvent_Binding::SMIL);
+  }
+}
+
 SVGViewBox* SVGElement::GetViewBox() { return nullptr; }
 
 nsAttrValue SVGElement::WillChangeViewBox() {
   return WillChangeValue(nsGkAtoms::viewBox);
 }
 
 void SVGElement::DidChangeViewBox(const nsAttrValue& aEmptyOrOldValue) {
   SVGViewBox* viewBox = GetViewBox();
@@ -2222,26 +2205,23 @@ UniquePtr<SMILAttr> SVGElement::GetAnima
       BooleanAttributesInfo info = GetBooleanInfo();
       for (uint32_t i = 0; i < info.mBooleanCount; i++) {
         if (aName == info.mBooleanInfo[i].mName) {
           return info.mBooleans[i].ToSMILAttr(this);
         }
       }
     }
 
-    // Angles:
-    {
-      AngleAttributesInfo info = GetAngleInfo();
-      for (uint32_t i = 0; i < info.mAngleCount; i++) {
-        if (aName == info.mAngleInfo[i].mName) {
-          return info.mAngles[i].ToSMILAttr(this);
-        }
-      }
+    // orient:
+    if (aName == nsGkAtoms::orient) {
+      SVGOrient* orient = GetOrient();
+      return orient ? orient->ToSMILAttr(this) : nullptr;
     }
 
+    // preserveAspectRatio:
     // viewBox:
     if (aName == nsGkAtoms::viewBox) {
       SVGViewBox* viewBox = GetViewBox();
       return viewBox ? viewBox->ToSMILAttr(this) : nullptr;
     }
 
     // preserveAspectRatio:
     if (aName == nsGkAtoms::preserveAspectRatio) {
--- a/dom/svg/SVGElement.h
+++ b/dom/svg/SVGElement.h
@@ -31,30 +31,30 @@ class nsSVGLength2;
 class nsSVGNumber2;
 
 nsresult NS_NewSVGElement(mozilla::dom::Element** aResult,
                           already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
 
 namespace mozilla {
 class DeclarationBlock;
 
-class SVGAngle;
 class SVGAnimatedNumberList;
 class SVGAnimatedPathSegList;
 class SVGAnimatedPointList;
 class SVGAnimatedPreserveAspectRatio;
 class SVGAnimatedTransformList;
 class SVGAnimatedLengthList;
 class SVGBoolean;
 class SVGEnum;
 class SVGUserUnitList;
 class SVGInteger;
 class SVGIntegerPair;
 class SVGNumberList;
 class SVGNumberPair;
+class SVGOrient;
 class SVGString;
 class SVGStringList;
 class DOMSVGStringList;
 class SVGViewBox;
 
 struct SVGEnumMapping;
 
 namespace dom {
@@ -177,17 +177,17 @@ class SVGElement : public SVGElementBase
     return GetNumberInfo().mNumberInfo[aAttrEnum].mPercentagesAllowed;
   }
   virtual bool HasValidDimensions() const { return true; }
   void SetLength(nsAtom* aName, const nsSVGLength2& aLength);
 
   nsAttrValue WillChangeLength(uint8_t aAttrEnum);
   nsAttrValue WillChangeNumberPair(uint8_t aAttrEnum);
   nsAttrValue WillChangeIntegerPair(uint8_t aAttrEnum);
-  nsAttrValue WillChangeAngle(uint8_t aAttrEnum);
+  nsAttrValue WillChangeOrient();
   nsAttrValue WillChangeViewBox();
   nsAttrValue WillChangePreserveAspectRatio();
   nsAttrValue WillChangeNumberList(uint8_t aAttrEnum);
   nsAttrValue WillChangeLengthList(uint8_t aAttrEnum);
   nsAttrValue WillChangePointList();
   nsAttrValue WillChangePathSegList();
   nsAttrValue WillChangeTransformList();
   nsAttrValue WillChangeStringList(bool aIsConditionalProcessingAttribute,
@@ -195,19 +195,19 @@ class SVGElement : public SVGElementBase
 
   void DidChangeLength(uint8_t aAttrEnum, const nsAttrValue& aEmptyOrOldValue);
   void DidChangeNumber(uint8_t aAttrEnum);
   void DidChangeNumberPair(uint8_t aAttrEnum,
                            const nsAttrValue& aEmptyOrOldValue);
   void DidChangeInteger(uint8_t aAttrEnum);
   void DidChangeIntegerPair(uint8_t aAttrEnum,
                             const nsAttrValue& aEmptyOrOldValue);
-  void DidChangeAngle(uint8_t aAttrEnum, const nsAttrValue& aEmptyOrOldValue);
   void DidChangeBoolean(uint8_t aAttrEnum);
   void DidChangeEnum(uint8_t aAttrEnum);
+  void DidChangeOrient(const nsAttrValue& aEmptyOrOldValue);
   void DidChangeViewBox(const nsAttrValue& aEmptyOrOldValue);
   void DidChangePreserveAspectRatio(const nsAttrValue& aEmptyOrOldValue);
   void DidChangeNumberList(uint8_t aAttrEnum,
                            const nsAttrValue& aEmptyOrOldValue);
   void DidChangeLengthList(uint8_t aAttrEnum,
                            const nsAttrValue& aEmptyOrOldValue);
   void DidChangePointList(const nsAttrValue& aEmptyOrOldValue);
   void DidChangePathSegList(const nsAttrValue& aEmptyOrOldValue);
@@ -217,19 +217,19 @@ class SVGElement : public SVGElementBase
                            uint8_t aAttrEnum,
                            const nsAttrValue& aEmptyOrOldValue);
 
   void DidAnimateLength(uint8_t aAttrEnum);
   void DidAnimateNumber(uint8_t aAttrEnum);
   void DidAnimateNumberPair(uint8_t aAttrEnum);
   void DidAnimateInteger(uint8_t aAttrEnum);
   void DidAnimateIntegerPair(uint8_t aAttrEnum);
-  void DidAnimateAngle(uint8_t aAttrEnum);
   void DidAnimateBoolean(uint8_t aAttrEnum);
   void DidAnimateEnum(uint8_t aAttrEnum);
+  void DidAnimateOrient();
   void DidAnimateViewBox();
   void DidAnimatePreserveAspectRatio();
   void DidAnimateNumberList(uint8_t aAttrEnum);
   void DidAnimateLengthList(uint8_t aAttrEnum);
   void DidAnimatePointList();
   void DidAnimatePathSegList();
   void DidAnimateTransformList(int32_t aModType);
   void DidAnimateString(uint8_t aAttrEnum);
@@ -438,34 +438,16 @@ class SVGElement : public SVGElementBase
                               uint32_t aIntegerPairCount)
         : mIntegerPairs(aIntegerPairs),
           mIntegerPairInfo(aIntegerPairInfo),
           mIntegerPairCount(aIntegerPairCount) {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
-  struct AngleInfo {
-    nsStaticAtom* const mName;
-    const float mDefaultValue;
-    const uint8_t mDefaultUnitType;
-  };
-
-  struct AngleAttributesInfo {
-    SVGAngle* const mAngles;
-    const AngleInfo* const mAngleInfo;
-    const uint32_t mAngleCount;
-
-    AngleAttributesInfo(SVGAngle* aAngles, AngleInfo* aAngleInfo,
-                        uint32_t aAngleCount)
-        : mAngles(aAngles), mAngleInfo(aAngleInfo), mAngleCount(aAngleCount) {}
-
-    void Reset(uint8_t aAttrEnum);
-  };
-
   struct BooleanInfo {
     nsStaticAtom* const mName;
     const bool mDefaultValue;
   };
 
   struct BooleanAttributesInfo {
     SVGBoolean* const mBooleans;
     const BooleanInfo* const mBooleanInfo;
@@ -590,21 +572,21 @@ class SVGElement : public SVGElementBase
     void Reset(uint8_t aAttrEnum);
   };
 
   virtual LengthAttributesInfo GetLengthInfo();
   virtual NumberAttributesInfo GetNumberInfo();
   virtual NumberPairAttributesInfo GetNumberPairInfo();
   virtual IntegerAttributesInfo GetIntegerInfo();
   virtual IntegerPairAttributesInfo GetIntegerPairInfo();
-  virtual AngleAttributesInfo GetAngleInfo();
   virtual BooleanAttributesInfo GetBooleanInfo();
   virtual EnumAttributesInfo GetEnumInfo();
-  // We assume all viewboxes and preserveAspectRatios are alike
+  // We assume all orients, viewboxes and preserveAspectRatios are alike
   // so we don't need to wrap the class
+  virtual SVGOrient* GetOrient();
   virtual SVGViewBox* GetViewBox();
   virtual SVGAnimatedPreserveAspectRatio* GetPreserveAspectRatio();
   virtual NumberListAttributesInfo GetNumberListInfo();
   virtual LengthListAttributesInfo GetLengthListInfo();
   virtual StringAttributesInfo GetStringInfo();
   virtual StringListAttributesInfo GetStringListInfo();
 
   static SVGEnumMapping sSVGUnitTypesMap[];
--- a/dom/svg/SVGMarkerElement.cpp
+++ b/dom/svg/SVGMarkerElement.cpp
@@ -48,46 +48,19 @@ SVGElement::LengthInfo SVGMarkerElement:
 SVGEnumMapping SVGMarkerElement::sUnitsMap[] = {
     {nsGkAtoms::strokeWidth, SVG_MARKERUNITS_STROKEWIDTH},
     {nsGkAtoms::userSpaceOnUse, SVG_MARKERUNITS_USERSPACEONUSE},
     {nullptr, 0}};
 
 SVGElement::EnumInfo SVGMarkerElement::sEnumInfo[1] = {
     {nsGkAtoms::markerUnits, sUnitsMap, SVG_MARKERUNITS_STROKEWIDTH}};
 
-SVGElement::AngleInfo SVGMarkerElement::sAngleInfo[1] = {
-    {nsGkAtoms::orient, 0, SVG_ANGLETYPE_UNSPECIFIED}};
-
 //----------------------------------------------------------------------
 // Implementation
 
-nsresult nsSVGOrientType::SetBaseValue(uint16_t aValue,
-                                       SVGElement* aSVGElement) {
-  if (aValue == SVG_MARKER_ORIENT_AUTO || aValue == SVG_MARKER_ORIENT_ANGLE ||
-      aValue == SVG_MARKER_ORIENT_AUTO_START_REVERSE) {
-    SetBaseValue(aValue);
-    aSVGElement->SetAttr(kNameSpaceID_None, nsGkAtoms::orient, nullptr,
-                         (aValue == SVG_MARKER_ORIENT_AUTO
-                              ? NS_LITERAL_STRING("auto")
-                              : aValue == SVG_MARKER_ORIENT_ANGLE
-                                    ? NS_LITERAL_STRING("0")
-                                    : NS_LITERAL_STRING("auto-start-reverse")),
-                         true);
-    return NS_OK;
-  }
-  return NS_ERROR_DOM_TYPE_ERR;
-}
-
-already_AddRefed<SVGAnimatedEnumeration> nsSVGOrientType::ToDOMAnimatedEnum(
-    SVGElement* aSVGElement) {
-  RefPtr<SVGAnimatedEnumeration> toReturn =
-      new DOMAnimatedEnum(this, aSVGElement);
-  return toReturn.forget();
-}
-
 SVGMarkerElement::SVGMarkerElement(
     already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
     : SVGMarkerElementBase(std::move(aNodeInfo)), mCoordCtx(nullptr) {}
 
 //----------------------------------------------------------------------
 // nsINode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGMarkerElement)
@@ -121,36 +94,34 @@ already_AddRefed<SVGAnimatedLength> SVGM
   return mLengthAttributes[MARKERWIDTH].ToDOMAnimatedLength(this);
 }
 
 already_AddRefed<SVGAnimatedLength> SVGMarkerElement::MarkerHeight() {
   return mLengthAttributes[MARKERHEIGHT].ToDOMAnimatedLength(this);
 }
 
 already_AddRefed<SVGAnimatedEnumeration> SVGMarkerElement::OrientType() {
-  return mOrientType.ToDOMAnimatedEnum(this);
+  return mOrient.ToDOMAnimatedEnum(this);
 }
 
 already_AddRefed<SVGAnimatedAngle> SVGMarkerElement::OrientAngle() {
-  return mAngleAttributes[ORIENT].ToDOMAnimatedAngle(this);
+  return mOrient.ToDOMAnimatedAngle(this);
 }
 
 void SVGMarkerElement::SetOrientToAuto() {
-  SetAttr(kNameSpaceID_None, nsGkAtoms::orient, nullptr,
-          NS_LITERAL_STRING("auto"), true);
+  mOrient.SetBaseType(SVG_MARKER_ORIENT_AUTO, this);
 }
 
 void SVGMarkerElement::SetOrientToAngle(DOMSVGAngle& angle, ErrorResult& rv) {
   float f = angle.Value();
   if (!IsFinite(f)) {
     rv.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
     return;
   }
-  mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
-  mAngleAttributes[ORIENT].SetBaseValue(f, angle.UnitType(), this, true);
+  mOrient.SetBaseValue(f, angle.UnitType(), this, true);
 }
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(bool)
 SVGMarkerElement::IsAttributeMapped(const nsAtom* name) const {
   static const MappedAttributeEntry* const map[] = {sFEFloodMap,
@@ -167,58 +138,16 @@ SVGMarkerElement::IsAttributeMapped(cons
 
   return FindAttributeDependence(name, map) ||
          SVGMarkerElementBase::IsAttributeMapped(name);
 }
 
 //----------------------------------------------------------------------
 // SVGElement methods
 
-bool SVGMarkerElement::ParseAttribute(int32_t aNameSpaceID, nsAtom* aName,
-                                      const nsAString& aValue,
-                                      nsIPrincipal* aMaybeScriptedPrincipal,
-                                      nsAttrValue& aResult) {
-  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::orient) {
-    if (aValue.EqualsLiteral("auto")) {
-      mOrientType.SetBaseValue(SVG_MARKER_ORIENT_AUTO);
-      aResult.SetTo(aValue);
-      mAngleAttributes[ORIENT].SetBaseValue(0.f, SVG_ANGLETYPE_UNSPECIFIED,
-                                            this, false);
-      return true;
-    }
-    if (aValue.EqualsLiteral("auto-start-reverse")) {
-      mOrientType.SetBaseValue(SVG_MARKER_ORIENT_AUTO_START_REVERSE);
-      aResult.SetTo(aValue);
-      mAngleAttributes[ORIENT].SetBaseValue(0.f, SVG_ANGLETYPE_UNSPECIFIED,
-                                            this, false);
-      return true;
-    }
-    mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
-  }
-  return SVGMarkerElementBase::ParseAttribute(aNameSpaceID, aName, aValue,
-                                              aMaybeScriptedPrincipal, aResult);
-}
-
-nsresult SVGMarkerElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
-                                        const nsAttrValue* aValue,
-                                        const nsAttrValue* aOldValue,
-                                        nsIPrincipal* aMaybeScriptedPrincipal,
-                                        bool aNotify) {
-  if (!aValue && aNamespaceID == kNameSpaceID_None &&
-      aName == nsGkAtoms::orient) {
-    mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
-  }
-
-  return SVGMarkerElementBase::AfterSetAttr(
-      aNamespaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
-}
-
-//----------------------------------------------------------------------
-// SVGElement methods
-
 void SVGMarkerElement::SetParentCoordCtxProvider(SVGViewportElement* aContext) {
   mCoordCtx = aContext;
   mViewBoxToViewportTransform = nullptr;
 }
 
 /* virtual */ bool SVGMarkerElement::HasValidDimensions() const {
   return (!mLengthAttributes[MARKERWIDTH].IsExplicitlySet() ||
           mLengthAttributes[MARKERWIDTH].GetAnimValInSpecifiedUnits() > 0) &&
@@ -226,25 +155,22 @@ void SVGMarkerElement::SetParentCoordCtx
           mLengthAttributes[MARKERHEIGHT].GetAnimValInSpecifiedUnits() > 0);
 }
 
 SVGElement::LengthAttributesInfo SVGMarkerElement::GetLengthInfo() {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               ArrayLength(sLengthInfo));
 }
 
-SVGElement::AngleAttributesInfo SVGMarkerElement::GetAngleInfo() {
-  return AngleAttributesInfo(mAngleAttributes, sAngleInfo,
-                             ArrayLength(sAngleInfo));
-}
-
 SVGElement::EnumAttributesInfo SVGMarkerElement::GetEnumInfo() {
   return EnumAttributesInfo(mEnumAttributes, sEnumInfo, ArrayLength(sEnumInfo));
 }
 
+SVGOrient* SVGMarkerElement::GetOrient() { return &mOrient; }
+
 SVGViewBox* SVGMarkerElement::GetViewBox() { return &mViewBox; }
 
 SVGAnimatedPreserveAspectRatio* SVGMarkerElement::GetPreserveAspectRatio() {
   return &mPreserveAspectRatio;
 }
 
 //----------------------------------------------------------------------
 // public helpers
@@ -252,25 +178,25 @@ SVGAnimatedPreserveAspectRatio* SVGMarke
 gfx::Matrix SVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
                                                  const SVGMark& aMark) {
   float scale =
       mEnumAttributes[MARKERUNITS].GetAnimValue() == SVG_MARKERUNITS_STROKEWIDTH
           ? aStrokeWidth
           : 1.0f;
 
   float angle;
-  switch (mOrientType.GetAnimValueInternal()) {
+  switch (mOrient.GetAnimType()) {
     case SVG_MARKER_ORIENT_AUTO:
       angle = aMark.angle;
       break;
     case SVG_MARKER_ORIENT_AUTO_START_REVERSE:
       angle = aMark.angle + (aMark.type == SVGMark::eStart ? M_PI : 0.0f);
       break;
     default:  // SVG_MARKER_ORIENT_ANGLE
-      angle = mAngleAttributes[ORIENT].GetAnimValue() * M_PI / 180.0f;
+      angle = mOrient.GetAnimValue() * M_PI / 180.0f;
       break;
   }
 
   return gfx::Matrix(cos(angle) * scale, sin(angle) * scale,
                      -sin(angle) * scale, cos(angle) * scale, aMark.x, aMark.y);
 }
 
 SVGViewBoxRect SVGMarkerElement::GetViewBoxRect() {
--- a/dom/svg/SVGMarkerElement.h
+++ b/dom/svg/SVGMarkerElement.h
@@ -3,22 +3,23 @@
 /* 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_SVGMarkerElement_h
 #define mozilla_dom_SVGMarkerElement_h
 
 #include "nsAutoPtr.h"
-#include "SVGAngle.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "SVGEnum.h"
 #include "nsSVGLength2.h"
+#include "SVGOrient.h"
 #include "SVGViewBox.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/SVGAnimatedAngle.h"
 #include "mozilla/dom/SVGAnimatedEnumeration.h"
 #include "mozilla/dom/SVGElement.h"
 #include "mozilla/dom/SVGMarkerElementBinding.h"
 
 class nsSVGMarkerFrame;
 
 nsresult NS_NewSVGMarkerElement(
     nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
@@ -27,66 +28,16 @@ namespace mozilla {
 
 struct SVGMark;
 
 namespace dom {
 
 // Non-Exposed Marker Orientation Types
 static const uint16_t SVG_MARKER_ORIENT_AUTO_START_REVERSE = 3;
 
-class nsSVGOrientType {
- public:
-  nsSVGOrientType()
-      : mAnimVal(SVGMarkerElement_Binding::SVG_MARKER_ORIENT_ANGLE),
-        mBaseVal(SVGMarkerElement_Binding::SVG_MARKER_ORIENT_ANGLE) {}
-
-  nsresult SetBaseValue(uint16_t aValue, SVGElement* aSVGElement);
-
-  // XXX FIXME like https://bugzilla.mozilla.org/show_bug.cgi?id=545550 but
-  // without adding an mIsAnimated member...?
-  void SetBaseValue(uint16_t aValue) { mAnimVal = mBaseVal = uint8_t(aValue); }
-  // no need to notify, since SVGAngle does that
-  void SetAnimValue(uint16_t aValue) { mAnimVal = uint8_t(aValue); }
-
-  // we want to avoid exposing SVG_MARKER_ORIENT_AUTO_START_REVERSE to
-  // Web content
-  uint16_t GetBaseValue() const {
-    return mAnimVal == SVG_MARKER_ORIENT_AUTO_START_REVERSE
-               ? SVGMarkerElement_Binding::SVG_MARKER_ORIENT_UNKNOWN
-               : mBaseVal;
-  }
-  uint16_t GetAnimValue() const {
-    return mAnimVal == SVG_MARKER_ORIENT_AUTO_START_REVERSE
-               ? SVGMarkerElement_Binding::SVG_MARKER_ORIENT_UNKNOWN
-               : mAnimVal;
-  }
-  uint16_t GetAnimValueInternal() const { return mAnimVal; }
-
-  already_AddRefed<SVGAnimatedEnumeration> ToDOMAnimatedEnum(
-      SVGElement* aSVGElement);
-
- private:
-  SVGEnumValue mAnimVal;
-  SVGEnumValue mBaseVal;
-
-  struct DOMAnimatedEnum final : public SVGAnimatedEnumeration {
-    DOMAnimatedEnum(nsSVGOrientType* aVal, SVGElement* aSVGElement)
-        : SVGAnimatedEnumeration(aSVGElement), mVal(aVal) {}
-
-    nsSVGOrientType* mVal;  // kept alive because it belongs to content
-
-    using mozilla::dom::SVGAnimatedEnumeration::SetBaseVal;
-    virtual uint16_t BaseVal() override { return mVal->GetBaseValue(); }
-    virtual void SetBaseVal(uint16_t aBaseVal, ErrorResult& aRv) override {
-      aRv = mVal->SetBaseValue(aBaseVal, mSVGElement);
-    }
-    virtual uint16_t AnimVal() override { return mVal->GetAnimValue(); }
-  };
-};
-
 typedef SVGElement SVGMarkerElementBase;
 
 class SVGMarkerElement : public SVGMarkerElementBase {
   friend class ::nsSVGMarkerFrame;
 
  protected:
   friend nsresult(::NS_NewSVGMarkerElement(
       nsIContent** aResult,
@@ -95,80 +46,61 @@ class SVGMarkerElement : public SVGMarke
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
   virtual JSObject* WrapNode(JSContext* cx,
                              JS::Handle<JSObject*> aGivenProto) override;
 
  public:
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* name) const override;
 
-  virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
-                                const nsAttrValue* aValue,
-                                const nsAttrValue* aOldValue,
-                                nsIPrincipal* aMaybeScriptedPrincipal,
-                                bool aNotify) override;
-
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const override;
 
   // public helpers
   gfx::Matrix GetMarkerTransform(float aStrokeWidth, const SVGMark& aMark);
   SVGViewBoxRect GetViewBoxRect();
   gfx::Matrix GetViewBoxTransform();
 
   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
 
-  nsSVGOrientType* GetOrientType() { return &mOrientType; }
-
   // WebIDL
   already_AddRefed<SVGAnimatedRect> ViewBox();
   already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
   already_AddRefed<SVGAnimatedLength> RefX();
   already_AddRefed<SVGAnimatedLength> RefY();
   already_AddRefed<SVGAnimatedEnumeration> MarkerUnits();
   already_AddRefed<SVGAnimatedLength> MarkerWidth();
   already_AddRefed<SVGAnimatedLength> MarkerHeight();
   already_AddRefed<SVGAnimatedEnumeration> OrientType();
   already_AddRefed<SVGAnimatedAngle> OrientAngle();
   void SetOrientToAuto();
   void SetOrientToAngle(DOMSVGAngle& angle, ErrorResult& rv);
 
  protected:
-  virtual bool ParseAttribute(int32_t aNameSpaceID, nsAtom* aName,
-                              const nsAString& aValue,
-                              nsIPrincipal* aMaybeScriptedPrincipal,
-                              nsAttrValue& aResult) override;
-
   void SetParentCoordCtxProvider(SVGViewportElement* aContext);
 
   virtual LengthAttributesInfo GetLengthInfo() override;
-  virtual AngleAttributesInfo GetAngleInfo() override;
   virtual EnumAttributesInfo GetEnumInfo() override;
+  virtual SVGOrient* GetOrient() override;
   virtual SVGViewBox* GetViewBox() override;
   virtual SVGAnimatedPreserveAspectRatio* GetPreserveAspectRatio() override;
 
   enum { REFX, REFY, MARKERWIDTH, MARKERHEIGHT };
   nsSVGLength2 mLengthAttributes[4];
   static LengthInfo sLengthInfo[4];
 
   enum { MARKERUNITS };
   SVGEnum mEnumAttributes[1];
   static SVGEnumMapping sUnitsMap[];
   static EnumInfo sEnumInfo[1];
 
-  enum { ORIENT };
-  SVGAngle mAngleAttributes[1];
-  static AngleInfo sAngleInfo[1];
-
+  SVGOrient mOrient;
   SVGViewBox mViewBox;
   SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
 
-  // derived properties (from 'orient') handled separately
-  nsSVGOrientType mOrientType;
-
   SVGViewportElement* mCoordCtx;
   nsAutoPtr<gfx::Matrix> mViewBoxToViewportTransform;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_SVGMarkerElement_h
--- a/dom/svg/SVGMotionSMILAnimationFunction.cpp
+++ b/dom/svg/SVGMotionSMILAnimationFunction.cpp
@@ -8,17 +8,17 @@
 
 #include "mozilla/dom/SVGAnimationElement.h"
 #include "mozilla/dom/SVGPathElement.h"
 #include "mozilla/dom/SVGMPathElement.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/SMILParserUtils.h"
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
-#include "SVGAngle.h"
+#include "SVGOrient.h"
 #include "SVGMotionSMILPathUtils.h"
 #include "SVGMotionSMILType.h"
 #include "SVGPathDataParser.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::SVGAngle_Binding;
 using namespace mozilla::gfx;
 
@@ -386,26 +386,26 @@ nsresult SVGMotionSMILAnimationFunction:
   if (aRotate.EqualsLiteral("auto")) {
     mRotateType = eRotateType_Auto;
   } else if (aRotate.EqualsLiteral("auto-reverse")) {
     mRotateType = eRotateType_AutoReverse;
   } else {
     mRotateType = eRotateType_Explicit;
 
     uint16_t angleUnit;
-    if (!SVGAngle::GetValueFromString(aRotate, mRotateAngle, &angleUnit)) {
+    if (!SVGOrient::GetValueFromString(aRotate, mRotateAngle, &angleUnit)) {
       mRotateAngle = 0.0f;  // set default rotate angle
       // XXX report to console?
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
 
     // Convert to radian units, if we're not already in radians.
     if (angleUnit != SVG_ANGLETYPE_RAD) {
-      mRotateAngle *= SVGAngle::GetDegreesPerUnit(angleUnit) /
-                      SVGAngle::GetDegreesPerUnit(SVG_ANGLETYPE_RAD);
+      mRotateAngle *= SVGOrient::GetDegreesPerUnit(angleUnit) /
+                      SVGOrient::GetDegreesPerUnit(SVG_ANGLETYPE_RAD);
     }
   }
   return NS_OK;
 }
 
 void SVGMotionSMILAnimationFunction::UnsetRotate() {
   mRotateAngle = 0.0f;  // default value
   mRotateType = eRotateType_Explicit;
rename from dom/svg/SVGAngle.cpp
rename to dom/svg/SVGOrient.cpp
--- a/dom/svg/SVGAngle.cpp
+++ b/dom/svg/SVGOrient.cpp
@@ -1,15 +1,15 @@
 /* -*- 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/. */
 
-#include "SVGAngle.h"
+#include "SVGOrient.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Move.h"
 #include "mozilla/SMILValue.h"
 #include "mozilla/dom/DOMSVGAngle.h"
 #include "mozilla/dom/SVGAnimatedAngle.h"
 #include "mozilla/dom/SVGMarkerElement.h"
 #include "nsContentUtils.h"
@@ -23,23 +23,61 @@ using namespace mozilla::dom::SVGMarkerE
 
 namespace mozilla {
 
 static const nsStaticAtom* const angleUnitMap[] = {
     nullptr, /* SVG_ANGLETYPE_UNKNOWN */
     nullptr, /* SVG_ANGLETYPE_UNSPECIFIED */
     nsGkAtoms::deg, nsGkAtoms::rad, nsGkAtoms::grad};
 
-static SVGAttrTearoffTable<SVGAngle, SVGAnimatedAngle>
+static SVGAttrTearoffTable<SVGOrient, SVGAnimatedEnumeration>
+    sSVGAnimatedEnumTearoffTable;
+static SVGAttrTearoffTable<SVGOrient, SVGAnimatedAngle>
     sSVGAnimatedAngleTearoffTable;
-static SVGAttrTearoffTable<SVGAngle, DOMSVGAngle> sBaseSVGAngleTearoffTable;
-static SVGAttrTearoffTable<SVGAngle, DOMSVGAngle> sAnimSVGAngleTearoffTable;
+static SVGAttrTearoffTable<SVGOrient, DOMSVGAngle> sBaseSVGAngleTearoffTable;
+static SVGAttrTearoffTable<SVGOrient, DOMSVGAngle> sAnimSVGAngleTearoffTable;
 
 /* Helper functions */
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangeOrientNotifier
+// Stack-based helper class to pair calls to WillChangeOrient and
+// DidChangeOrient.
+class MOZ_RAII AutoChangeOrientNotifier {
+ public:
+  explicit AutoChangeOrientNotifier(
+      SVGOrient* aOrient, SVGElement* aSVGElement,
+      bool aDoSetAttr = true MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mOrient(aOrient), mSVGElement(aSVGElement), mDoSetAttr(aDoSetAttr) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mOrient, "Expecting non-null orient");
+    if (mSVGElement && mDoSetAttr) {
+      mEmptyOrOldValue = mSVGElement->WillChangeOrient();
+    }
+  }
+
+  ~AutoChangeOrientNotifier() {
+    if (mSVGElement) {
+      if (mDoSetAttr) {
+        mSVGElement->DidChangeOrient(mEmptyOrOldValue);
+      }
+      if (mOrient->mIsAnimated) {
+        mSVGElement->AnimationNeedsResample();
+      }
+    }
+  }
+
+ private:
+  SVGOrient* const mOrient;
+  SVGElement* const mSVGElement;
+  nsAttrValue mEmptyOrOldValue;
+  bool mDoSetAttr;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 static bool IsValidAngleUnitType(uint16_t unit) {
   if (unit > SVG_ANGLETYPE_UNKNOWN && unit <= SVG_ANGLETYPE_GRAD) return true;
 
   return false;
 }
 
 static void GetAngleUnitString(nsAString& unit, uint16_t unitType) {
   if (IsValidAngleUnitType(unitType)) {
@@ -72,125 +110,113 @@ static void GetAngleValueString(nsAStrin
                                 uint16_t aUnitType) {
   nsTextFormatter::ssprintf(aValueAsString, u"%g", (double)aValue);
 
   nsAutoString unitString;
   GetAngleUnitString(unitString, aUnitType);
   aValueAsString.Append(unitString);
 }
 
-/* static */ bool SVGAngle::GetValueFromString(const nsAString& aString,
-                                               float& aValue,
-                                               uint16_t* aUnitType) {
+/* static */ bool SVGOrient::GetValueFromString(const nsAString& aString,
+                                                float& aValue,
+                                                uint16_t* aUnitType) {
   RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString);
   const RangedPtr<const char16_t> end =
       SVGContentUtils::GetEndRangedPtr(aString);
 
   if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
     return false;
   }
 
   const nsAString& units = Substring(iter.get(), end.get());
   *aUnitType = GetAngleUnitTypeForString(units);
   return IsValidAngleUnitType(*aUnitType);
 }
 
-/* static */ float SVGAngle::GetDegreesPerUnit(uint8_t aUnit) {
+/* static */ float SVGOrient::GetDegreesPerUnit(uint8_t aUnit) {
   switch (aUnit) {
     case SVG_ANGLETYPE_UNSPECIFIED:
     case SVG_ANGLETYPE_DEG:
       return 1;
     case SVG_ANGLETYPE_RAD:
       return static_cast<float>(180.0 / M_PI);
     case SVG_ANGLETYPE_GRAD:
       return 90.0f / 100.0f;
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown unit type");
       return 0;
   }
 }
 
-void SVGAngle::SetBaseValueInSpecifiedUnits(float aValue,
-                                            SVGElement* aSVGElement) {
-  if (mBaseVal == aValue) {
+void SVGOrient::SetBaseValueInSpecifiedUnits(float aValue,
+                                             SVGElement* aSVGElement) {
+  if (mBaseVal == aValue && mBaseType == SVG_MARKER_ORIENT_ANGLE) {
     return;
   }
 
-  nsAttrValue emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
+  AutoChangeOrientNotifier notifier(this, aSVGElement);
+
   mBaseVal = aValue;
+  mBaseType = SVG_MARKER_ORIENT_ANGLE;
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
-  } else {
-    aSVGElement->AnimationNeedsResample();
+    mAnimType = mBaseType;
   }
-  aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
 }
 
-nsresult SVGAngle::ConvertToSpecifiedUnits(uint16_t unitType,
-                                           SVGElement* aSVGElement) {
+nsresult SVGOrient::ConvertToSpecifiedUnits(uint16_t unitType,
+                                            SVGElement* aSVGElement) {
   if (!IsValidAngleUnitType(unitType)) return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 
-  if (mBaseValUnit == uint8_t(unitType)) return NS_OK;
-
-  nsAttrValue emptyOrOldValue;
-  if (aSVGElement) {
-    emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
+  if (mBaseValUnit == uint8_t(unitType) &&
+      mBaseType == SVG_MARKER_ORIENT_ANGLE) {
+    return NS_OK;
   }
 
   float valueInUserUnits = mBaseVal * GetDegreesPerUnit(mBaseValUnit);
-  // Setting aDoSetAttr to false here will ensure we don't call
-  // Will/DidChangeAngle a second time (and dispatch duplicate notifications).
-  SetBaseValue(valueInUserUnits, unitType, aSVGElement, false);
-
-  if (aSVGElement) {
-    aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
-  }
+  SetBaseValue(valueInUserUnits, unitType, aSVGElement, true);
 
   return NS_OK;
 }
 
-nsresult SVGAngle::NewValueSpecifiedUnits(uint16_t unitType,
-                                          float valueInSpecifiedUnits,
-                                          SVGElement* aSVGElement) {
+nsresult SVGOrient::NewValueSpecifiedUnits(uint16_t unitType,
+                                           float valueInSpecifiedUnits,
+                                           SVGElement* aSVGElement) {
   NS_ENSURE_FINITE(valueInSpecifiedUnits, NS_ERROR_ILLEGAL_VALUE);
 
   if (!IsValidAngleUnitType(unitType)) return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 
-  if (mBaseVal == valueInSpecifiedUnits && mBaseValUnit == uint8_t(unitType))
+  if (mBaseVal == valueInSpecifiedUnits && mBaseValUnit == uint8_t(unitType) &&
+      mBaseType == SVG_MARKER_ORIENT_ANGLE)
     return NS_OK;
 
-  nsAttrValue emptyOrOldValue;
-  if (aSVGElement) {
-    emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
-  }
+  AutoChangeOrientNotifier notifier(this, aSVGElement);
+
   mBaseVal = valueInSpecifiedUnits;
   mBaseValUnit = uint8_t(unitType);
+  mBaseType = SVG_MARKER_ORIENT_ANGLE;
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
     mAnimValUnit = mBaseValUnit;
-  } else {
-    aSVGElement->AnimationNeedsResample();
-  }
-  if (aSVGElement) {
-    aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
+    mAnimType = mBaseType;
   }
   return NS_OK;
 }
 
-already_AddRefed<DOMSVGAngle> SVGAngle::ToDOMBaseVal(SVGElement* aSVGElement) {
+already_AddRefed<DOMSVGAngle> SVGOrient::ToDOMBaseVal(SVGElement* aSVGElement) {
   RefPtr<DOMSVGAngle> domBaseVal = sBaseSVGAngleTearoffTable.GetTearoff(this);
   if (!domBaseVal) {
     domBaseVal = new DOMSVGAngle(this, aSVGElement, DOMSVGAngle::BaseValue);
     sBaseSVGAngleTearoffTable.AddTearoff(this, domBaseVal);
   }
 
   return domBaseVal.forget();
 }
 
-already_AddRefed<DOMSVGAngle> SVGAngle::ToDOMAnimVal(SVGElement* aSVGElement) {
+already_AddRefed<DOMSVGAngle> SVGOrient::ToDOMAnimVal(SVGElement* aSVGElement) {
   RefPtr<DOMSVGAngle> domAnimVal = sAnimSVGAngleTearoffTable.GetTearoff(this);
   if (!domAnimVal) {
     domAnimVal = new DOMSVGAngle(this, aSVGElement, DOMSVGAngle::AnimValue);
     sAnimSVGAngleTearoffTable.AddTearoff(this, domAnimVal);
   }
 
   return domAnimVal.forget();
 }
@@ -202,169 +228,256 @@ DOMSVGAngle::~DOMSVGAngle() {
     sAnimSVGAngleTearoffTable.RemoveTearoff(mVal);
   } else {
     delete mVal;
   }
 }
 
 /* Implementation */
 
-nsresult SVGAngle::SetBaseValueString(const nsAString& aValueAsString,
-                                      SVGElement* aSVGElement,
-                                      bool aDoSetAttr) {
+nsresult SVGOrient::SetBaseValueString(const nsAString& aValueAsString,
+                                       SVGElement* aSVGElement,
+                                       bool aDoSetAttr) {
+  uint8_t type;
   float value;
   uint16_t unitType;
+  bool valueChanged = false;
 
-  if (!GetValueFromString(aValueAsString, value, &unitType)) {
-    return NS_ERROR_DOM_SYNTAX_ERR;
-  }
-  if (mBaseVal == value && mBaseValUnit == uint8_t(unitType)) {
-    return NS_OK;
+  if (aValueAsString.EqualsLiteral("auto")) {
+    type = SVG_MARKER_ORIENT_AUTO;
+    if (type == mBaseType) {
+      return NS_OK;
+    }
+  } else if (aValueAsString.EqualsLiteral("auto-start-reverse")) {
+    type = SVG_MARKER_ORIENT_AUTO_START_REVERSE;
+    if (type == mBaseType) {
+      return NS_OK;
+    }
+  } else {
+    if (!GetValueFromString(aValueAsString, value, &unitType)) {
+      return NS_ERROR_DOM_SYNTAX_ERR;
+    }
+    if (mBaseVal == value && mBaseValUnit == uint8_t(unitType) &&
+        mBaseType == SVG_MARKER_ORIENT_ANGLE) {
+      return NS_OK;
+    }
+    valueChanged = true;
   }
 
-  nsAttrValue emptyOrOldValue;
-  if (aDoSetAttr) {
-    emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
+  AutoChangeOrientNotifier notifier(this, aSVGElement, aDoSetAttr);
+
+  if (valueChanged) {
+    mBaseVal = value;
+    mBaseValUnit = uint8_t(unitType);
+    mBaseType = SVG_MARKER_ORIENT_ANGLE;
+  } else {
+    mBaseVal = .0f;
+    mBaseValUnit = SVG_ANGLETYPE_UNSPECIFIED;
+    mBaseType = type;
   }
-  mBaseVal = value;
-  mBaseValUnit = uint8_t(unitType);
+
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
     mAnimValUnit = mBaseValUnit;
-  } else {
-    aSVGElement->AnimationNeedsResample();
+    mAnimType = mBaseType;
   }
 
-  if (aDoSetAttr) {
-    aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
-  }
   return NS_OK;
 }
 
-void SVGAngle::GetBaseValueString(nsAString& aValueAsString) const {
+void SVGOrient::GetBaseValueString(nsAString& aValueAsString) const {
+  switch (mBaseType) {
+    case SVG_MARKER_ORIENT_AUTO:
+      aValueAsString.AssignLiteral("auto");
+      return;
+    case SVG_MARKER_ORIENT_AUTO_START_REVERSE:
+      aValueAsString.AssignLiteral("auto-start-reverse");
+      return;
+  }
   GetAngleValueString(aValueAsString, mBaseVal, mBaseValUnit);
 }
 
-void SVGAngle::GetAnimValueString(nsAString& aValueAsString) const {
+void SVGOrient::GetBaseAngleValueString(nsAString& aValueAsString) const {
+  GetAngleValueString(aValueAsString, mBaseVal, mBaseValUnit);
+}
+
+void SVGOrient::GetAnimAngleValueString(nsAString& aValueAsString) const {
   GetAngleValueString(aValueAsString, mAnimVal, mAnimValUnit);
 }
 
-void SVGAngle::SetBaseValue(float aValue, uint8_t aUnit,
-                            SVGElement* aSVGElement, bool aDoSetAttr) {
+void SVGOrient::SetBaseValue(float aValue, uint8_t aUnit,
+                             SVGElement* aSVGElement, bool aDoSetAttr) {
   float valueInSpecifiedUnits = aValue / GetDegreesPerUnit(aUnit);
-  if (aUnit == mBaseValUnit && mBaseVal == valueInSpecifiedUnits) {
+  if (aUnit == mBaseValUnit && mBaseVal == valueInSpecifiedUnits &&
+      mBaseType == SVG_MARKER_ORIENT_ANGLE) {
     return;
   }
-  nsAttrValue emptyOrOldValue;
-  if (aSVGElement && aDoSetAttr) {
-    emptyOrOldValue = aSVGElement->WillChangeAngle(mAttrEnum);
-  }
+
+  AutoChangeOrientNotifier notifier(this, aSVGElement, aDoSetAttr);
 
   mBaseValUnit = aUnit;
   mBaseVal = valueInSpecifiedUnits;
+  mBaseType = SVG_MARKER_ORIENT_ANGLE;
   if (!mIsAnimated) {
+    mAnimValUnit = mBaseValUnit;
     mAnimVal = mBaseVal;
-  } else {
-    aSVGElement->AnimationNeedsResample();
-  }
-  if (aSVGElement && aDoSetAttr) {
-    aSVGElement->DidChangeAngle(mAttrEnum, emptyOrOldValue);
+    mAnimType = mBaseType;
   }
 }
 
-void SVGAngle::SetAnimValue(float aValue, uint8_t aUnit,
-                            SVGElement* aSVGElement) {
-  if (mIsAnimated && mAnimVal == aValue && mAnimValUnit == aUnit) {
+nsresult SVGOrient::SetBaseType(SVGEnumValue aValue, SVGElement* aSVGElement) {
+  if (mBaseType == aValue) {
+    return NS_OK;
+  }
+  if (aValue == SVG_MARKER_ORIENT_AUTO || aValue == SVG_MARKER_ORIENT_ANGLE ||
+      aValue == SVG_MARKER_ORIENT_AUTO_START_REVERSE) {
+    AutoChangeOrientNotifier notifier(this, aSVGElement);
+
+    mBaseVal = .0f;
+    mBaseValUnit = SVG_ANGLETYPE_UNSPECIFIED;
+    mBaseType = aValue;
+    if (!mIsAnimated) {
+      mAnimVal = mBaseVal;
+      mAnimValUnit = mBaseValUnit;
+      mAnimType = mBaseType;
+    }
+    return NS_OK;
+  }
+  return NS_ERROR_DOM_TYPE_ERR;
+}
+
+void SVGOrient::SetAnimValue(float aValue, uint8_t aUnit,
+                             SVGElement* aSVGElement) {
+  if (mIsAnimated && mAnimVal == aValue && mAnimValUnit == aUnit &&
+      mAnimType == SVG_MARKER_ORIENT_ANGLE) {
     return;
   }
   mAnimVal = aValue;
   mAnimValUnit = aUnit;
+  mAnimType = SVG_MARKER_ORIENT_ANGLE;
   mIsAnimated = true;
-  aSVGElement->DidAnimateAngle(mAttrEnum);
+  aSVGElement->DidAnimateOrient();
 }
 
-already_AddRefed<SVGAnimatedAngle> SVGAngle::ToDOMAnimatedAngle(
+void SVGOrient::SetAnimType(SVGEnumValue aValue, SVGElement* aSVGElement) {
+  if (mIsAnimated && mAnimType == aValue) {
+    return;
+  }
+  mAnimVal = .0f;
+  mAnimValUnit = SVG_ANGLETYPE_UNSPECIFIED;
+  mAnimType = aValue;
+  mIsAnimated = true;
+  aSVGElement->DidAnimateOrient();
+}
+
+already_AddRefed<SVGAnimatedAngle> SVGOrient::ToDOMAnimatedAngle(
     SVGElement* aSVGElement) {
   RefPtr<SVGAnimatedAngle> domAnimatedAngle =
       sSVGAnimatedAngleTearoffTable.GetTearoff(this);
   if (!domAnimatedAngle) {
     domAnimatedAngle = new SVGAnimatedAngle(this, aSVGElement);
     sSVGAnimatedAngleTearoffTable.AddTearoff(this, domAnimatedAngle);
   }
 
   return domAnimatedAngle.forget();
 }
 
+already_AddRefed<SVGAnimatedEnumeration> SVGOrient::ToDOMAnimatedEnum(
+    SVGElement* aSVGElement) {
+  RefPtr<SVGAnimatedEnumeration> domAnimatedEnum =
+      sSVGAnimatedEnumTearoffTable.GetTearoff(this);
+  if (!domAnimatedEnum) {
+    domAnimatedEnum = new DOMAnimatedEnum(this, aSVGElement);
+    sSVGAnimatedEnumTearoffTable.AddTearoff(this, domAnimatedEnum);
+  }
+
+  return domAnimatedEnum.forget();
+}
+
 SVGAnimatedAngle::~SVGAnimatedAngle() {
   sSVGAnimatedAngleTearoffTable.RemoveTearoff(mVal);
 }
 
-UniquePtr<SMILAttr> SVGAngle::ToSMILAttr(SVGElement* aSVGElement) {
+SVGOrient::DOMAnimatedEnum::~DOMAnimatedEnum() {
+  sSVGAnimatedEnumTearoffTable.RemoveTearoff(mVal);
+}
+
+// we want to avoid exposing SVG_MARKER_ORIENT_AUTO_START_REVERSE to
+// Web content
+uint16_t SVGOrient::DOMAnimatedEnum::Sanitize(uint16_t aValue) {
+  return aValue == dom::SVG_MARKER_ORIENT_AUTO_START_REVERSE
+             ? dom::SVGMarkerElement_Binding::SVG_MARKER_ORIENT_UNKNOWN
+             : aValue;
+}
+
+UniquePtr<SMILAttr> SVGOrient::ToSMILAttr(SVGElement* aSVGElement) {
   if (aSVGElement->NodeInfo()->Equals(nsGkAtoms::marker, kNameSpaceID_SVG)) {
-    SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(aSVGElement);
-    return MakeUnique<SMILOrient>(marker->GetOrientType(), this, aSVGElement);
+    return MakeUnique<SMILOrient>(this, aSVGElement);
   }
   // SMILOrient would not be useful for general angle attributes (also,
   // "orient" is the only animatable <angle>-valued attribute in SVG 1.1).
   MOZ_ASSERT_UNREACHABLE("Trying to animate unknown angle attribute.");
   return nullptr;
 }
 
-nsresult SVGAngle::SMILOrient::ValueFromString(
+nsresult SVGOrient::SMILOrient::ValueFromString(
     const nsAString& aStr, const SVGAnimationElement* /*aSrcElement*/,
     SMILValue& aValue, bool& aPreventCachingOfSandwich) const {
   SMILValue val(&SVGOrientSMILType::sSingleton);
   if (aStr.EqualsLiteral("auto")) {
     val.mU.mOrient.mOrientType = SVG_MARKER_ORIENT_AUTO;
+    val.mU.mOrient.mAngle = .0f;
+    val.mU.mOrient.mUnit = SVG_ANGLETYPE_UNSPECIFIED;
   } else if (aStr.EqualsLiteral("auto-start-reverse")) {
     val.mU.mOrient.mOrientType = SVG_MARKER_ORIENT_AUTO_START_REVERSE;
+    val.mU.mOrient.mAngle = .0f;
+    val.mU.mOrient.mUnit = SVG_ANGLETYPE_UNSPECIFIED;
   } else {
     float value;
     uint16_t unitType;
     if (!GetValueFromString(aStr, value, &unitType)) {
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
     val.mU.mOrient.mAngle = value;
     val.mU.mOrient.mUnit = unitType;
     val.mU.mOrient.mOrientType = SVG_MARKER_ORIENT_ANGLE;
   }
   aValue = std::move(val);
   aPreventCachingOfSandwich = false;
 
   return NS_OK;
 }
 
-SMILValue SVGAngle::SMILOrient::GetBaseValue() const {
+SMILValue SVGOrient::SMILOrient::GetBaseValue() const {
   SMILValue val(&SVGOrientSMILType::sSingleton);
-  val.mU.mOrient.mAngle = mAngle->GetBaseValInSpecifiedUnits();
-  val.mU.mOrient.mUnit = mAngle->GetBaseValueUnit();
-  val.mU.mOrient.mOrientType = mOrientType->GetBaseValue();
+  val.mU.mOrient.mAngle = mOrient->GetBaseValInSpecifiedUnits();
+  val.mU.mOrient.mUnit = mOrient->GetBaseValueUnit();
+  val.mU.mOrient.mOrientType = mOrient->mBaseType;
   return val;
 }
 
-void SVGAngle::SMILOrient::ClearAnimValue() {
-  if (mAngle->mIsAnimated) {
-    mOrientType->SetAnimValue(mOrientType->GetBaseValue());
-    mAngle->mIsAnimated = false;
-    mAngle->mAnimVal = mAngle->mBaseVal;
-    mAngle->mAnimValUnit = mAngle->mBaseValUnit;
-    mSVGElement->DidAnimateAngle(mAngle->mAttrEnum);
+void SVGOrient::SMILOrient::ClearAnimValue() {
+  if (mOrient->mIsAnimated) {
+    mOrient->mIsAnimated = false;
+    mOrient->mAnimVal = mOrient->mBaseVal;
+    mOrient->mAnimValUnit = mOrient->mBaseValUnit;
+    mOrient->mAnimType = mOrient->mBaseType;
+    mSVGElement->DidAnimateOrient();
   }
 }
 
-nsresult SVGAngle::SMILOrient::SetAnimValue(const SMILValue& aValue) {
+nsresult SVGOrient::SMILOrient::SetAnimValue(const SMILValue& aValue) {
   NS_ASSERTION(aValue.mType == &SVGOrientSMILType::sSingleton,
                "Unexpected type to assign animated value");
 
   if (aValue.mType == &SVGOrientSMILType::sSingleton) {
-    mOrientType->SetAnimValue(aValue.mU.mOrient.mOrientType);
     if (aValue.mU.mOrient.mOrientType == SVG_MARKER_ORIENT_AUTO ||
         aValue.mU.mOrient.mOrientType == SVG_MARKER_ORIENT_AUTO_START_REVERSE) {
-      mAngle->SetAnimValue(0.0f, SVG_ANGLETYPE_UNSPECIFIED, mSVGElement);
+      mOrient->SetAnimType(aValue.mU.mOrient.mOrientType, mSVGElement);
     } else {
-      mAngle->SetAnimValue(aValue.mU.mOrient.mAngle, aValue.mU.mOrient.mUnit,
-                           mSVGElement);
+      mOrient->SetAnimValue(aValue.mU.mOrient.mAngle, aValue.mU.mOrient.mUnit,
+                            mSVGElement);
     }
   }
   return NS_OK;
 }
 
 }  // namespace mozilla
rename from dom/svg/SVGAngle.h
rename to dom/svg/SVGOrient.h
--- a/dom/svg/SVGAngle.h
+++ b/dom/svg/SVGOrient.h
@@ -1,125 +1,149 @@
 /* -*- 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 __NS_SVGANGLE_H__
-#define __NS_SVGANGLE_H__
+#ifndef __NS_SVGORIENT_H__
+#define __NS_SVGORIENT_H__
 
 #include "nsError.h"
+#include "SVGEnum.h"
 #include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/SMILAttr.h"
 #include "mozilla/dom/SVGAngleBinding.h"
+#include "mozilla/dom/SVGAnimatedEnumeration.h"
+#include "mozilla/dom/SVGMarkerElementBinding.h"
 #include "mozilla/UniquePtr.h"
 
 class nsISupports;
 
 namespace mozilla {
 
 class SMILValue;
 
 namespace dom {
-class nsSVGOrientType;
 class DOMSVGAngle;
 class SVGAnimatedAngle;
 class SVGAnimationElement;
 class SVGElement;
 }  // namespace dom
 
-class SVGAngle {
+class SVGOrient {
+  friend class AutoChangeOrientNotifier;
   friend class mozilla::dom::DOMSVGAngle;
   friend class mozilla::dom::SVGAnimatedAngle;
   typedef mozilla::dom::SVGElement SVGElement;
 
  public:
-  void Init(uint8_t aAttrEnum = 0xff, float aValue = 0,
-            uint8_t aUnitType =
-                mozilla::dom::SVGAngle_Binding::SVG_ANGLETYPE_UNSPECIFIED) {
-    mAnimVal = mBaseVal = aValue;
-    mAnimValUnit = mBaseValUnit = aUnitType;
-    mAttrEnum = aAttrEnum;
+  void Init() {
+    mAnimVal = mBaseVal = .0f;
+    mAnimType = mBaseType =
+        dom::SVGMarkerElement_Binding::SVG_MARKER_ORIENT_ANGLE;
+    mAnimValUnit = mBaseValUnit =
+        dom::SVGAngle_Binding::SVG_ANGLETYPE_UNSPECIFIED;
     mIsAnimated = false;
   }
 
   nsresult SetBaseValueString(const nsAString& aValue, SVGElement* aSVGElement,
                               bool aDoSetAttr);
   void GetBaseValueString(nsAString& aValue) const;
-  void GetAnimValueString(nsAString& aValue) const;
+  void GetBaseAngleValueString(nsAString& aValue) const;
+  void GetAnimAngleValueString(nsAString& aValue) const;
 
   float GetBaseValue() const {
     return mBaseVal * GetDegreesPerUnit(mBaseValUnit);
   }
   float GetAnimValue() const {
     return mAnimVal * GetDegreesPerUnit(mAnimValUnit);
   }
+  SVGEnumValue GetAnimType() const { return mAnimType; }
 
   void SetBaseValue(float aValue, uint8_t aUnit, SVGElement* aSVGElement,
                     bool aDoSetAttr);
+  nsresult SetBaseType(SVGEnumValue aValue, SVGElement* aSVGElement);
   void SetAnimValue(float aValue, uint8_t aUnit, SVGElement* aSVGElement);
+  void SetAnimType(SVGEnumValue aType, SVGElement* aSVGElement);
 
   uint8_t GetBaseValueUnit() const { return mBaseValUnit; }
   uint8_t GetAnimValueUnit() const { return mAnimValUnit; }
   float GetBaseValInSpecifiedUnits() const { return mBaseVal; }
   float GetAnimValInSpecifiedUnits() const { return mAnimVal; }
 
   static nsresult ToDOMSVGAngle(nsISupports** aResult);
-  already_AddRefed<mozilla::dom::SVGAnimatedAngle> ToDOMAnimatedAngle(
+  already_AddRefed<dom::SVGAnimatedAngle> ToDOMAnimatedAngle(
       SVGElement* aSVGElement);
-  mozilla::UniquePtr<SMILAttr> ToSMILAttr(SVGElement* aSVGElement);
+  already_AddRefed<dom::SVGAnimatedEnumeration> ToDOMAnimatedEnum(
+      SVGElement* aSVGElement);
+  UniquePtr<SMILAttr> ToSMILAttr(SVGElement* aSVGElement);
 
   static bool GetValueFromString(const nsAString& aString, float& aValue,
                                  uint16_t* aUnitType);
   static float GetDegreesPerUnit(uint8_t aUnit);
 
  private:
   float mAnimVal;
   float mBaseVal;
+  uint8_t mAnimType;
+  uint8_t mBaseType;
   uint8_t mAnimValUnit;
   uint8_t mBaseValUnit;
-  uint8_t mAttrEnum;  // element specified tracking for attribute
   bool mIsAnimated;
 
   void SetBaseValueInSpecifiedUnits(float aValue, SVGElement* aSVGElement);
   nsresult NewValueSpecifiedUnits(uint16_t aUnitType, float aValue,
                                   SVGElement* aSVGElement);
   nsresult ConvertToSpecifiedUnits(uint16_t aUnitType, SVGElement* aSVGElement);
-  already_AddRefed<mozilla::dom::DOMSVGAngle> ToDOMBaseVal(
-      SVGElement* aSVGElement);
-  already_AddRefed<mozilla::dom::DOMSVGAngle> ToDOMAnimVal(
-      SVGElement* aSVGElement);
+  already_AddRefed<dom::DOMSVGAngle> ToDOMBaseVal(SVGElement* aSVGElement);
+  already_AddRefed<dom::DOMSVGAngle> ToDOMAnimVal(SVGElement* aSVGElement);
 
  public:
-  // We do not currently implemente a SMILAngle struct because in SVG 1.1 the
-  // only *animatable* attribute that takes an <angle> is 'orient', on the
-  // 'marker' element, and 'orient' must be special cased since it can also
-  // take the value 'auto', making it a more complex type.
+  struct DOMAnimatedEnum final : public dom::SVGAnimatedEnumeration {
+    DOMAnimatedEnum(SVGOrient* aVal, SVGElement* aSVGElement)
+        : SVGAnimatedEnumeration(aSVGElement), mVal(aVal) {}
+    ~DOMAnimatedEnum();
+
+    SVGOrient* mVal;  // kept alive because it belongs to content
+
+    using mozilla::dom::SVGAnimatedEnumeration::SetBaseVal;
+    uint16_t BaseVal() override { return Sanitize(mVal->mBaseType); }
+    void SetBaseVal(uint16_t aBaseVal, ErrorResult& aRv) override {
+      aRv = mVal->SetBaseType(aBaseVal, mSVGElement);
+    }
+    uint16_t AnimVal() override {
+      // Script may have modified animation parameters or timeline -- DOM
+      // getters need to flush any resample requests to reflect these
+      // modifications.
+      mSVGElement->FlushAnimations();
+      return Sanitize(mVal->mAnimType);
+    }
+
+   private:
+    uint16_t Sanitize(uint16_t aValue);
+  };
 
   struct SMILOrient final : public SMILAttr {
    public:
-    SMILOrient(mozilla::dom::nsSVGOrientType* aOrientType, SVGAngle* aAngle,
-               SVGElement* aSVGElement)
-        : mOrientType(aOrientType), mAngle(aAngle), mSVGElement(aSVGElement) {}
+    SMILOrient(SVGOrient* aOrient, SVGElement* aSVGElement)
+        : mOrient(aOrient), mSVGElement(aSVGElement) {}
 
     // These will stay alive because a SMILAttr only lives as long
     // as the Compositing step, and DOM elements don't get a chance to
     // die during that.
-    mozilla::dom::nsSVGOrientType* mOrientType;
-    SVGAngle* mAngle;
+    SVGOrient* mOrient;
     SVGElement* mSVGElement;
 
     // SMILAttr methods
     virtual nsresult ValueFromString(
-        const nsAString& aStr,
-        const mozilla::dom::SVGAnimationElement* aSrcElement, SMILValue& aValue,
-        bool& aPreventCachingOfSandwich) const override;
+        const nsAString& aStr, const dom::SVGAnimationElement* aSrcElement,
+        SMILValue& aValue, bool& aPreventCachingOfSandwich) const override;
     virtual SMILValue GetBaseValue() const override;
     virtual void ClearAnimValue() override;
     virtual nsresult SetAnimValue(const SMILValue& aValue) override;
   };
 };
 
 }  // namespace mozilla
 
-#endif  //__NS_SVGANGLE_H__
+#endif  //__NS_SVGORIENT_H__
--- a/dom/svg/SVGOrientSMILType.cpp
+++ b/dom/svg/SVGOrientSMILType.cpp
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SVGOrientSMILType.h"
 
 #include "mozilla/SMILValue.h"
 #include "mozilla/dom/SVGMarkerElement.h"
 #include "nsDebug.h"
-#include "SVGAngle.h"
+#include "SVGOrient.h"
 #include <math.h>
 
 namespace mozilla {
 
 using namespace dom::SVGAngle_Binding;
 using namespace dom::SVGMarkerElement_Binding;
 
 /*static*/ SVGOrientSMILType SVGOrientSMILType::sSingleton;
@@ -64,26 +64,26 @@ nsresult SVGOrientSMILType::Add(SMILValu
       aValueToAdd.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE) {
     // TODO: it would be nice to be able to add to auto angles
     return NS_ERROR_FAILURE;
   }
 
   // We may be dealing with two different angle units, so we normalize to
   // degrees for the add:
   float currentAngle = aDest.mU.mOrient.mAngle *
-                       SVGAngle::GetDegreesPerUnit(aDest.mU.mOrient.mUnit);
-  float angleToAdd = aValueToAdd.mU.mOrient.mAngle *
-                     SVGAngle::GetDegreesPerUnit(aValueToAdd.mU.mOrient.mUnit) *
-                     aCount;
+                       SVGOrient::GetDegreesPerUnit(aDest.mU.mOrient.mUnit);
+  float angleToAdd =
+      aValueToAdd.mU.mOrient.mAngle *
+      SVGOrient::GetDegreesPerUnit(aValueToAdd.mU.mOrient.mUnit) * aCount;
 
   // And then we give the resulting animated value the same units as the value
   // that we're animating to/by (i.e. the same as aValueToAdd):
   aDest.mU.mOrient.mAngle =
       (currentAngle + angleToAdd) /
-      SVGAngle::GetDegreesPerUnit(aValueToAdd.mU.mOrient.mUnit);
+      SVGOrient::GetDegreesPerUnit(aValueToAdd.mU.mOrient.mUnit);
   aDest.mU.mOrient.mUnit = aValueToAdd.mU.mOrient.mUnit;
 
   return NS_OK;
 }
 
 nsresult SVGOrientSMILType::ComputeDistance(const SMILValue& aFrom,
                                             const SMILValue& aTo,
                                             double& aDistance) const {
@@ -93,19 +93,19 @@ nsresult SVGOrientSMILType::ComputeDista
   if (aFrom.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE ||
       aTo.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE) {
     // TODO: it would be nice to be able to compute distance with auto angles
     return NS_ERROR_FAILURE;
   }
 
   // Normalize both to degrees in case they're different angle units:
   double from = aFrom.mU.mOrient.mAngle *
-                SVGAngle::GetDegreesPerUnit(aFrom.mU.mOrient.mUnit);
-  double to =
-      aTo.mU.mOrient.mAngle * SVGAngle::GetDegreesPerUnit(aTo.mU.mOrient.mUnit);
+                SVGOrient::GetDegreesPerUnit(aFrom.mU.mOrient.mUnit);
+  double to = aTo.mU.mOrient.mAngle *
+              SVGOrient::GetDegreesPerUnit(aTo.mU.mOrient.mUnit);
 
   aDistance = fabs(to - from);
 
   return NS_OK;
 }
 
 nsresult SVGOrientSMILType::Interpolate(const SMILValue& aStartVal,
                                         const SMILValue& aEndVal,
@@ -118,22 +118,22 @@ nsresult SVGOrientSMILType::Interpolate(
 
   if (aStartVal.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE ||
       aEndVal.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE) {
     // TODO: it would be nice to be able to handle auto angles too.
     return NS_ERROR_FAILURE;
   }
 
   float start = aStartVal.mU.mOrient.mAngle *
-                SVGAngle::GetDegreesPerUnit(aStartVal.mU.mOrient.mUnit);
+                SVGOrient::GetDegreesPerUnit(aStartVal.mU.mOrient.mUnit);