Merge mozilla-inbound to mozilla-central. a=merge
authorCosmin Sabou <csabou@mozilla.com>
Fri, 15 Feb 2019 20:39:45 +0200
changeset 459552 8961019ee4c6fe27e6319d9cf9ea6867b4f3c7bb
parent 459551 0e2ab35d382d2bcb9ebaee2a9eac3c1541f861d7 (current diff)
parent 459482 43678f936e37673d325bd3bf3d300ea69aad5bae (diff)
child 459553 db3c4f90508207462b85037b1a69c563b1a6b88e
child 459616 7465be2b8821fe89f5bbf1df01e07d2d81f25568
push id111964
push usercsabou@mozilla.com
push dateFri, 15 Feb 2019 18:54:44 +0000
treeherdermozilla-inbound@db3c4f905082 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
8961019ee4c6 / 67.0a1 / 20190215184035 / files
nightly linux64
8961019ee4c6 / 67.0a1 / 20190215184035 / files
nightly mac
8961019ee4c6 / 67.0a1 / 20190215184035 / files
nightly win32
8961019ee4c6 / 67.0a1 / 20190215184035 / files
nightly win64
8961019ee4c6 / 67.0a1 / 20190215184035 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
Cargo.lock
browser/base/content/browser.js
browser/components/BrowserContentHandler.jsm
browser/components/build/nsModule.cpp
browser/components/extensions/ExtensionControlledPopup.jsm
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/wasm/WasmIonCompile.cpp
layout/painting/nsDisplayList.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.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
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/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/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/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) {
--- 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/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/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).
@@ -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) {
@@ -728,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 = [];
@@ -831,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
@@ -298,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) {
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/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/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/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']
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}
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',
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);
   float end = aEndVal.mU.mOrient.mAngle *
-              SVGAngle::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
+              SVGOrient::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
   float result = (start + (end - start) * aUnitDistance);
 
   // Again, we use the unit of the to/by value for the result:
   aResult.mU.mOrient.mAngle =
-      result / SVGAngle::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
+      result / SVGOrient::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
   aResult.mU.mOrient.mUnit = aEndVal.mU.mOrient.mUnit;
 
   return NS_OK;
 }
 
 }  // namespace mozilla
--- a/dom/svg/moz.build
+++ b/dom/svg/moz.build
@@ -121,17 +121,16 @@ UNIFIED_SOURCES += [
     'DOMSVGPointList.cpp',
     'DOMSVGStringList.cpp',
     'DOMSVGTransform.cpp',
     'DOMSVGTransformList.cpp',
     'nsISVGPoint.cpp',
     'nsSVGLength2.cpp',
     'nsSVGNumber2.cpp',
     'SVGAElement.cpp',
-    'SVGAngle.cpp',
     'SVGAnimatedAngle.cpp',
     'SVGAnimatedBoolean.cpp',
     'SVGAnimatedEnumeration.cpp',
     'SVGAnimatedInteger.cpp',
     'SVGAnimatedLength.cpp',
     'SVGAnimatedLengthList.cpp',
     'SVGAnimatedNumber.cpp',
     'SVGAnimatedNumberList.cpp',
@@ -204,16 +203,17 @@ UNIFIED_SOURCES += [
     'SVGMotionSMILAttr.cpp',
     'SVGMotionSMILPathUtils.cpp',
     'SVGMotionSMILType.cpp',
     'SVGMPathElement.cpp',
     'SVGNumberList.cpp',
     'SVGNumberListSMILType.cpp',
     'SVGNumberPair.cpp',
     'SVGNumberPairSMILType.cpp',
+    'SVGOrient.cpp',
     'SVGOrientSMILType.cpp',
     'SVGPathData.cpp',
     'SVGPathDataParser.cpp',
     'SVGPathElement.cpp',
     'SVGPathSegListSMILType.cpp',
     'SVGPathSegUtils.cpp',
     'SVGPatternElement.cpp',
     'SVGPointList.cpp',
rename from dom/system/NetworkGeolocationProvider.js
rename to dom/system/NetworkGeolocationProvider.jsm
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.jsm
@@ -413,9 +413,9 @@ WifiGeoPositionProvider.prototype = {
     function notifyPositionUnavailable(listener) {
       if (listener) {
         listener.notifyError(POSITION_UNAVAILABLE);
       }
     }
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WifiGeoPositionProvider]);
+var EXPORTED_SYMBOLS = ["WifiGeoPositionProvider"];
deleted file mode 100644
--- a/dom/system/NetworkGeolocationProvider.manifest
+++ /dev/null
@@ -1,3 +0,0 @@
-component {77DA64D3-7458-4920-9491-86CC9914F904} NetworkGeolocationProvider.js
-contract @mozilla.org/geolocation/provider;1 {77DA64D3-7458-4920-9491-86CC9914F904}
-contract @mozilla.org/geolocation/mls-provider;1 {77DA64D3-7458-4920-9491-86CC9914F904}
new file mode 100644
--- /dev/null
+++ b/dom/system/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': '{77DA64D3-7458-4920-9491-86CC9914F904}',
+        'contract_ids': [
+            '@mozilla.org/geolocation/provider;1',
+            '@mozilla.org/geolocation/mls-provider;1',
+        ],
+        'jsm': 'resource://gre/modules/NetworkGeolocationProvider.jsm',
+        'constructor': 'WifiGeoPositionProvider',
+    },
+]
--- a/dom/system/moz.build
+++ b/dom/system/moz.build
@@ -74,19 +74,22 @@ EXPORTS.mozilla += [
 ]
 
 UNIFIED_SOURCES += [
     'nsDeviceSensors.cpp',
     'nsOSPermissionRequestBase.cpp',
     'OSFileConstants.cpp',
 ]
 
-EXTRA_COMPONENTS += [
-    'NetworkGeolocationProvider.js',
-    'NetworkGeolocationProvider.manifest',
+EXTRA_JS_MODULES += [
+    'NetworkGeolocationProvider.jsm',
+]
+
+XPCOM_MANIFESTS += [
+    'components.conf',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 # We fire the nsDOMDeviceAcceleration
 LOCAL_INCLUDES += [
     '/dom/base',
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -93,12 +93,8 @@ MOCHITEST_CHROME_MANIFESTS += [
 ]
 
 XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
-
-if CONFIG['NIGHTLY_BUILD']:
-    DEFINES['ENABLE_WASM_REFTYPES'] = True
-    DEFINES['ENABLE_WASM_GC'] = True
--- a/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js
+++ b/extensions/cookie/test/unit/test_permmanager_migrate_4-7_no_history.js
@@ -18,22 +18,21 @@ var factory = {
   QueryInterface: ChromeUtils.generateQI([Ci.nsIFactory])
 };
 
 var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
 
 var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 var oldClassID = registrar.contractIDToCID(CONTRACT_ID);
 var oldFactory = Components.manager.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
-registrar.unregisterFactory(oldClassID, oldFactory);
 registrar.registerFactory(newClassID, "", CONTRACT_ID, factory);
 
 function cleanupFactory() {
   registrar.unregisterFactory(newClassID, factory);
-  registrar.registerFactory(oldClassID, "", CONTRACT_ID, oldFactory);
+  registrar.registerFactory(oldClassID, "", CONTRACT_ID, null);
 }
 
 function GetPermissionsFile(profile)
 {
   let file = profile.clone();
   file.append(PERMISSIONS_FILE_NAME);
   return file;
 }
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-53000
+53005
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -15298,16 +15298,18 @@ artifice/RSMZ
 artificer/M
 artificial/Y
 artificiality/M
 artillery/M
 artilleryman/M
 artillerymen
 artiness/M
 artisan/MS
+artisanal/Y
+artisanship/S
 artist/MS
 artiste/MS
 artistic/I
 artistically
 artistry/M
 artless/PY
 artlessness/M
 artsy/TR
@@ -16726,16 +16728,17 @@ bidding/M
 biddy/SM
 bide/S
 bidet/MS
 bidirectional/Y
 biennial/MYS
 biennium/MS
 bier/M
 biff/SGD
+bifida
 bifocal/S
 bifocals/M
 bifurcate/XDSGN
 bifurcation/M
 big/P
 bigamist/SM
 bigamous
 bigamy/M
@@ -18565,16 +18568,17 @@ cardigan/SM
 cardinal/SMY
 cardinality/S
 cardio
 cardiogram/SM
 cardiograph/M
 cardiographs
 cardiologist/MS
 cardiology/M
+cardiomegaly
 cardiomyopathy
 cardiopulmonary
 cardiovascular
 cardsharp/MRZS
 cardsharper/M
 care/SM
 careen/DGS
 career/MDGS
@@ -46398,16 +46402,17 @@ spigot/SM
 spike/DSMG
 spikiness/M
 spiky/RPT
 spill/SMDG
 spillage/MS
 spillover/SM
 spillway/MS
 spin/MS
+spina
 spinach/M
 spinal/SMY
 spindle/MGDS
 spindly/TR
 spine/SM
 spineless/YP
 spinet/SM
 spinless
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -382,18 +382,18 @@ class ImageContainer final : public Supp
 
   /**
    * Create ImageContainer just to hold another ASYNCHRONOUS ImageContainer's
    * async container ID.
    * @param aAsyncContainerID async container ID for which we are a proxy
    */
   explicit ImageContainer(const CompositableHandle& aHandle);
 
-  typedef uint32_t FrameID;
-  typedef uint32_t ProducerID;
+  typedef ContainerFrameID FrameID;
+  typedef ContainerProducerID ProducerID;
 
   RefPtr<PlanarYCbCrImage> CreatePlanarYCbCrImage();
 
   // Factory methods for shared image types.
   RefPtr<SharedRGBImage> CreateSharedRGBImage();
 
   struct NonOwningImage {
     explicit NonOwningImage(Image* aImage = nullptr,
--- a/gfx/layers/ImageTypes.h
+++ b/gfx/layers/ImageTypes.h
@@ -2,16 +2,18 @@
 /* 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 GFX_IMAGETYPES_H
 #define GFX_IMAGETYPES_H
 
+#include <stdint.h>     // for uint32_t
+
 namespace mozilla {
 
 enum class ImageFormat {
   /**
    * The PLANAR_YCBCR format creates a PlanarYCbCrImage. All backends should
    * support this format, because the Ogg video decoder depends on it.
    * The maximum image width and height is 16384.
    */
@@ -101,11 +103,21 @@ enum class StereoMode {
 
 enum class YUVColorSpace {
   BT601,
   BT709,
   // This represents the unknown format.
   UNKNOWN,
 };
 
+namespace layers {
+
+typedef uint32_t ContainerFrameID;
+constexpr ContainerFrameID kContainerFrameID_Invalid = 0;
+
+typedef uint32_t ContainerProducerID;
+constexpr ContainerProducerID kContainerProducerID_Invalid = 0;
+
+}  // namespace layers
+
 }  // namespace mozilla
 
 #endif
--- a/gfx/layers/ipc/SharedSurfacesChild.cpp
+++ b/gfx/layers/ipc/SharedSurfacesChild.cpp
@@ -320,31 +320,41 @@ SharedSurfacesChild::AsSourceSurfaceShar
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   return Share(sharedSurface, aManager, aResources, aKey);
 }
 
 /* static */ nsresult SharedSurfacesChild::Share(
     ImageContainer* aContainer, RenderRootStateManager* aManager,
-    wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey) {
+    wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey,
+    ContainerProducerID aProducerId) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aContainer);
   MOZ_ASSERT(aManager);
 
   if (aContainer->IsAsync()) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   AutoTArray<ImageContainer::OwningImage, 4> images;
   aContainer->GetCurrentImages(&images);
   if (images.IsEmpty()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
+  if (aProducerId != kContainerProducerID_Invalid &&
+      images[0].mProducerID != aProducerId) {
+    // If the producer ID of the surface in the container does not match the
+    // expected producer ID, then we do not want to proceed with sharing. This
+    // is useful for when callers are unsure if given container is for the same
+    // producer / underlying image request.
+    return NS_ERROR_FAILURE;
+  }
+
   RefPtr<gfx::SourceSurface> surface = images[0].mImage->GetAsSourceSurface();
   if (!surface) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   auto sharedSurface = AsSourceSurfaceSharedData(surface);
   if (!sharedSurface) {
     return NS_ERROR_NOT_IMPLEMENTED;
--- a/gfx/layers/ipc/SharedSurfacesChild.h
+++ b/gfx/layers/ipc/SharedSurfacesChild.h
@@ -10,16 +10,17 @@
 #include <stdint.h>                            // for uint32_t, uint64_t
 #include "mozilla/Attributes.h"                // for override
 #include "mozilla/Maybe.h"                     // for Maybe
 #include "mozilla/RefPtr.h"                    // for already_AddRefed
 #include "mozilla/StaticPtr.h"                 // for StaticRefPtr
 #include "mozilla/gfx/UserData.h"              // for UserDataKey
 #include "mozilla/webrender/WebRenderTypes.h"  // for wr::ImageKey
 #include "nsTArray.h"                          // for AutoTArray
+#include "ImageTypes.h"                        // for ContainerProducerID
 
 namespace mozilla {
 namespace layers {
 class AnimationImageKeyData;
 }  // namespace layers
 }  // namespace mozilla
 
 template <>
@@ -86,17 +87,17 @@ class SharedSurfacesChild final {
    * mapped into the compositor thread's memory space, and a valid ImageKey be
    * generated for it for use with WebRender. If a different method should be
    * used to share the image data for this particular container, it will return
    * NS_ERROR_NOT_IMPLEMENTED. This must be called from the main thread.
    */
   static nsresult Share(ImageContainer* aContainer,
                         RenderRootStateManager* aManager,
                         wr::IpcResourceUpdateQueue& aResources,
-                        wr::ImageKey& aKey);
+                        wr::ImageKey& aKey, ContainerProducerID aProducerId);
 
   /**
    * Get the external ID, if any, bound to the shared surface. Used for memory
    * reporting purposes.
    */
   static Maybe<wr::ExternalImageId> GetExternalId(
       const gfx::SourceSurfaceSharedData* aSurface);
 
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -34,17 +34,17 @@ void WebRenderBackgroundData::AddWebRend
   if (data) {
     return data->IsAsync();
   }
 
   return false;
 }
 
 /* static */ bool WebRenderUserData::ProcessInvalidateForImage(
-    nsIFrame* aFrame, DisplayItemType aType) {
+    nsIFrame* aFrame, DisplayItemType aType, ContainerProducerID aProducerId) {
   MOZ_ASSERT(aFrame);
 
   if (!aFrame->HasProperty(WebRenderUserDataProperty::Key())) {
     return false;
   }
 
   auto type = static_cast<uint32_t>(aType);
   RefPtr<WebRenderFallbackData> fallback =
@@ -52,17 +52,17 @@ void WebRenderBackgroundData::AddWebRend
   if (fallback) {
     fallback->SetInvalid(true);
     aFrame->SchedulePaint();
     return true;
   }
 
   RefPtr<WebRenderImageData> image =
       GetWebRenderUserData<WebRenderImageData>(aFrame, type);
-  if (image && image->UsingSharedSurface()) {
+  if (image && image->UsingSharedSurface(aProducerId)) {
     return true;
   }
 
   aFrame->SchedulePaint();
   return false;
 }
 
 WebRenderUserData::WebRenderUserData(RenderRootStateManager* aManager,
@@ -102,27 +102,28 @@ WebRenderImageData::WebRenderImageData(R
 WebRenderImageData::~WebRenderImageData() {
   ClearImageKey();
 
   if (mPipelineId) {
     mManager->RemovePipelineIdForCompositable(mPipelineId.ref());
   }
 }
 
-bool WebRenderImageData::UsingSharedSurface() const {
+bool WebRenderImageData::UsingSharedSurface(
+    ContainerProducerID aProducerId) const {
   if (!mContainer || !mKey || mOwnsKey) {
     return false;
   }
 
   // If this is just an update with the same image key, then we know that the
   // share request initiated an asynchronous update so that we don't need to
   // rebuild the scene.
   wr::ImageKey key;
   nsresult rv = SharedSurfacesChild::Share(
-      mContainer, mManager, mManager->AsyncResourceUpdates(), key);
+      mContainer, mManager, mManager->AsyncResourceUpdates(), key, aProducerId);
   return NS_SUCCEEDED(rv) && mKey.ref() == key;
 }
 
 void WebRenderImageData::ClearImageKey() {
   if (mKey) {
     // If we don't own the key, then the owner is responsible for discarding the
     // key when appropriate.
     if (mOwnsKey) {
@@ -144,18 +145,18 @@ Maybe<wr::ImageKey> WebRenderImageData::
   MOZ_ASSERT(aContainer);
 
   if (mContainer != aContainer) {
     mContainer = aContainer;
   }
 
   wr::WrImageKey key;
   if (!aFallback) {
-    nsresult rv =
-        SharedSurfacesChild::Share(aContainer, mManager, aResources, key);
+    nsresult rv = SharedSurfacesChild::Share(aContainer, mManager, aResources,
+                                             key, kContainerProducerID_Invalid);
     if (NS_SUCCEEDED(rv)) {
       // Ensure that any previously owned keys are released before replacing. We
       // don't own this key, the surface itself owns it, so that it can be
       // shared across multiple elements.
       ClearImageKey();
       mKey = Some(key);
       return mKey;
     }
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -8,16 +8,17 @@
 #define GFX_WEBRENDERUSERDATA_H
 
 #include <vector>
 #include "BasicLayers.h"  // for BasicLayerManager
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/layers/AnimationInfo.h"
 #include "nsIFrame.h"
+#include "ImageTypes.h"
 
 class nsDisplayItemGeometry;
 
 namespace mozilla {
 namespace wr {
 class IpcResourceUpdateQueue;
 }
 
@@ -52,18 +53,18 @@ class WebRenderBackgroundData {
 /// to an nsFrame.
 class WebRenderUserData {
  public:
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderUserData>>
       WebRenderUserDataRefTable;
 
   static bool SupportsAsyncUpdate(nsIFrame* aFrame);
 
-  static bool ProcessInvalidateForImage(nsIFrame* aFrame,
-                                        DisplayItemType aType);
+  static bool ProcessInvalidateForImage(nsIFrame* aFrame, DisplayItemType aType,
+                                        ContainerProducerID aProducerId);
 
   NS_INLINE_DECL_REFCOUNTING(WebRenderUserData)
 
   WebRenderUserData(RenderRootStateManager* aManager, nsDisplayItem* aItem);
   WebRenderUserData(RenderRootStateManager* aManager, uint32_t mDisplayItemKey, nsIFrame* aFrame);
 
   virtual WebRenderImageData* AsImageData() { return nullptr; }
   virtual WebRenderFallbackData* AsFallbackData() { return nullptr; }
@@ -146,17 +147,17 @@ class WebRenderImageData : public WebRen
       const LayoutDeviceRect& aSCBounds, const gfx::Matrix4x4& aSCTransform,
       const gfx::MaybeIntSize& aScaleToSize, const wr::ImageRendering& aFilter,
       const wr::MixBlendMode& aMixBlendMode, bool aIsBackfaceVisible);
 
   void CreateImageClientIfNeeded();
 
   bool IsAsync() { return mPipelineId.isSome(); }
 
-  bool UsingSharedSurface() const;
+  bool UsingSharedSurface(ContainerProducerID aProducerId) const;
 
   void ClearImageKey();
 
  protected:
   Maybe<wr::ImageKey> mKey;
   RefPtr<TextureClient> mTextureOfImage;
   RefPtr<ImageClient> mImageClient;
   Maybe<wr::PipelineId> mPipelineId;
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -161,18 +161,17 @@ class gfxMacPlatformFontList : public gf
                           nsTArray<FamilyAndGeneric>* aOutput,
                           FindFamiliesFlags aFlags,
                           gfxFontStyle* aStyle = nullptr,
                           gfxFloat aDevToCssSize = 1.0) override;
 
   // lookup the system font for a particular system font type and set
   // the name and style characteristics
   void LookupSystemFont(mozilla::LookAndFeel::FontID aSystemFontID,
-                        nsACString& aSystemFontName, gfxFontStyle& aFontStyle,
-                        float aDevPixPerCSSPixel);
+                        nsACString& aSystemFontName, gfxFontStyle& aFontStyle);
 
   // Values for the entryType field in FontFamilyListEntry records passed
   // from chrome to content process.
   enum FontFamilyEntryType {
     kStandardFontFamily = 0,          // a standard installed font family
     kHiddenSystemFontFamily = 1,      // hidden system family, not exposed to UI
     kTextSizeSystemFontFamily = 2,    // name of 'system' font at text sizes
     kDisplaySizeSystemFontFamily = 3  // 'system' font at display sizes
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -1461,18 +1461,18 @@ bool gfxMacPlatformFontList::FindAndAddF
     aOutput->AppendElement(FindSystemFontFamily(mSystemTextFontFamilyName));
     return true;
   }
 
   return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, aFlags, aStyle, aDevToCssSize);
 }
 
 void gfxMacPlatformFontList::LookupSystemFont(LookAndFeel::FontID aSystemFontID,
-                                              nsACString& aSystemFontName, gfxFontStyle& aFontStyle,
-                                              float aDevPixPerCSSPixel) {
+                                              nsACString& aSystemFontName,
+                                              gfxFontStyle& aFontStyle) {
   // code moved here from widget/cocoa/nsLookAndFeel.mm
   NSFont* font = nullptr;
   char* systemFontName = nullptr;
   switch (aSystemFontID) {
     case LookAndFeel::eFont_MessageBox:
     case LookAndFeel::eFont_StatusBar:
     case LookAndFeel::eFont_List:
     case LookAndFeel::eFont_Field:
@@ -1523,18 +1523,17 @@ void gfxMacPlatformFontList::LookupSyste
   NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits];
   aFontStyle.style =
       (traits & NSFontItalicTrait) ? FontSlantStyle::Italic() : FontSlantStyle::Normal();
   aFontStyle.weight = (traits & NSFontBoldTrait) ? FontWeight::Bold() : FontWeight::Normal();
   aFontStyle.stretch =
       (traits & NSFontExpandedTrait)
           ? FontStretch::Expanded()
           : (traits & NSFontCondensedTrait) ? FontStretch::Condensed() : FontStretch::Normal();
-  // convert size from css pixels to device pixels
-  aFontStyle.size = [font pointSize] * aDevPixPerCSSPixel;
+  aFontStyle.size = [font pointSize];
   aFontStyle.systemFont = true;
 }
 
 // used to load system-wide font info on off-main thread
 class MacFontInfo : public FontInfoData {
  public:
   MacFontInfo(bool aLoadOtherNames, bool aLoadFaceNames, bool aLoadCmaps)
       : FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps) {}
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -316,20 +316,19 @@ void gfxPlatformMac::GetCommonFallbackFo
   }
 
   // Arial Unicode MS has lots of glyphs for obscure, use it as a last resort
   aFontList.AppendElement(kFontArialUnicodeMS);
 }
 
 /*static*/ void gfxPlatformMac::LookupSystemFont(
     mozilla::LookAndFeel::FontID aSystemFontID, nsACString& aSystemFontName,
-    gfxFontStyle& aFontStyle, float aDevPixPerCSSPixel) {
+    gfxFontStyle& aFontStyle) {
   gfxMacPlatformFontList* pfl = gfxMacPlatformFontList::PlatformFontList();
-  return pfl->LookupSystemFont(aSystemFontID, aSystemFontName, aFontStyle,
-                               aDevPixPerCSSPixel);
+  return pfl->LookupSystemFont(aSystemFontID, aSystemFontName, aFontStyle);
 }
 
 uint32_t gfxPlatformMac::ReadAntiAliasingThreshold() {
   uint32_t threshold = 0;  // default == no threshold
 
   // first read prefs flag to determine whether to use the setting or not
   bool useAntiAliasingThreshold =
       Preferences::GetBool("gfx.use_text_smoothing_setting", false);
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -48,18 +48,17 @@ class gfxPlatformMac : public gfxPlatfor
   virtual void GetCommonFallbackFonts(
       uint32_t aCh, uint32_t aNextCh, Script aRunScript,
       nsTArray<const char*>& aFontList) override;
 
   // lookup the system font for a particular system font type and set
   // the name and style characteristics
   static void LookupSystemFont(mozilla::LookAndFeel::FontID aSystemFontID,
                                nsACString& aSystemFontName,
-                               gfxFontStyle& aFontStyle,
-                               float aDevPixPerCSSPixel);
+                               gfxFontStyle& aFontStyle);
 
   virtual bool SupportsApzWheelInput() const override { return true; }
 
   bool RespectsFontStyleSmoothing() const override {
     // gfxMacFont respects the font smoothing hint.
     return true;
   }
 
--- a/image/DynamicImage.cpp
+++ b/image/DynamicImage.cpp
@@ -116,16 +116,22 @@ DynamicImage::GetOrientation() { return 
 
 NS_IMETHODIMP
 DynamicImage::GetType(uint16_t* aType) {
   *aType = imgIContainer::TYPE_RASTER;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+DynamicImage::GetProducerId(uint32_t* aId) {
+  *aId = 0;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 DynamicImage::GetAnimated(bool* aAnimated) {
   *aAnimated = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 DynamicImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
   IntSize size(mDrawable->Size());
--- a/image/Image.h
+++ b/image/Image.h
@@ -266,16 +266,20 @@ class ImageResource : public Image {
    * Illegal to use off-main-thread.
    */
   nsIURI* GetURI() const override { return mURI; }
 
  protected:
   explicit ImageResource(nsIURI* aURI);
   ~ImageResource();
 
+  layers::ContainerProducerID GetImageProducerId() const {
+    return mImageProducerID;
+  }
+
   bool GetSpecTruncatedTo1k(nsCString& aSpec) const;
 
   // Shared functionality for implementors of imgIContainer. Every
   // implementation of attribute animationMode should forward here.
   nsresult GetAnimationModeInternal(uint16_t* aAnimationMode);
   nsresult SetAnimationModeInternal(uint16_t aAnimationMode);
 
   /**
--- a/image/ImageWrapper.cpp
+++ b/image/ImageWrapper.cpp
@@ -127,16 +127,21 @@ ImageWrapper::GetIntrinsicRatio(nsSize* 
 
 NS_IMETHODIMP_(Orientation)
 ImageWrapper::GetOrientation() { return mInnerImage->GetOrientation(); }
 
 NS_IMETHODIMP
 ImageWrapper::GetType(uint16_t* aType) { return mInnerImage->GetType(aType); }
 
 NS_IMETHODIMP
+ImageWrapper::GetProducerId(uint32_t* aId) {
+  return mInnerImage->GetProducerId(aId);
+}
+
+NS_IMETHODIMP
 ImageWrapper::GetAnimated(bool* aAnimated) {
   return mInnerImage->GetAnimated(aAnimated);
 }
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 ImageWrapper::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
   return mInnerImage->GetFrame(aWhichFrame, aFlags);
 }
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -271,16 +271,24 @@ RasterImage::GetOrientation() { return m
 NS_IMETHODIMP
 RasterImage::GetType(uint16_t* aType) {
   NS_ENSURE_ARG_POINTER(aType);
 
   *aType = imgIContainer::TYPE_RASTER;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+RasterImage::GetProducerId(uint32_t* aId) {
+  NS_ENSURE_ARG_POINTER(aId);
+
+  *aId = ImageResource::GetImageProducerId();
+  return NS_OK;
+}
+
 LookupResult RasterImage::LookupFrameInternal(const IntSize& aSize,
                                               uint32_t aFlags,
                                               PlaybackType aPlaybackType,
                                               bool aMarkUsed) {
   if (mAnimationState && aPlaybackType == PlaybackType::eAnimated) {
     MOZ_ASSERT(mFrameAnimator);
     MOZ_ASSERT(ToSurfaceFlags(aFlags) == DefaultSurfaceFlags(),
                "Can't composite frames with non-default surface flags");
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -658,16 +658,25 @@ VectorImage::GetType(uint16_t* aType) {
   NS_ENSURE_ARG_POINTER(aType);
 
   *aType = imgIContainer::TYPE_VECTOR;
   return NS_OK;
 }
 
 //******************************************************************************
 NS_IMETHODIMP
+VectorImage::GetProducerId(uint32_t* aId) {
+  NS_ENSURE_ARG_POINTER(aId);
+
+  *aId = ImageResource::GetImageProducerId();
+  return NS_OK;
+}
+
+//******************************************************************************
+NS_IMETHODIMP
 VectorImage::GetAnimated(bool* aAnimated) {
   if (mError || !mIsFullyLoaded) {
     return NS_ERROR_FAILURE;
   }
 
   *aAnimated = mSVGDocumentWrapper->IsAnimated();
   return NS_OK;
 }
new file mode 100644
--- /dev/null
+++ b/image/build/components.conf
@@ -0,0 +1,66 @@
+# -*- 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/.
+
+Headers = [
+    '/image/build/nsImageModule.h',
+]
+
+InitFunc = 'mozilla::image::EnsureModuleInitialized'
+# This is called by LayoutModuleDtor to ensure it happens at the right time
+# during shutdown.
+# UnloadFunc = 'mozilla::image::ShutdownModule'
+
+Classes = [
+    # XXX We would like to get rid of the imgLoader factory constructor.  See the
+    # comment documenting the imgLoader constructor.
+    {
+        'cid': '{c1354898-e3fe-4602-88a7-c4520c21cb4e}',
+        'contract_ids': [
+            '@mozilla.org/image/cache;1',
+            '@mozilla.org/image/loader;1',
+        ],
+        'type': 'imgLoader',
+        'headers': ['imgLoader.h'],
+        'init_method': 'Init',
+        'categories': {'content-sniffing-services': '@mozilla.org/image/loader;1'},
+    },
+    {
+        'cid': '{20557898-1dd2-11b2-8f65-9c462ee2bc95}',
+        'contract_ids': ['@mozilla.org/image/request;1'],
+        'type': 'imgRequestProxy',
+        'headers': ['imgRequestProxy.h'],
+    },
+    {
+        'cid': '{3d8fa16d-c9e1-4b50-bdef-2c7ae249967a}',
+        'contract_ids': ['@mozilla.org/image/tools;1'],
+        'type': 'mozilla::image::imgTools',
+        'headers': ['/image/imgTools.h'],
+    },
+    {
+        'cid': '{13a5320c-4c91-4fa4-bd16-b081a3ba8c0b}',
+        'contract_ids': ['@mozilla.org/image/encoder;2?type=image/bmp'],
+        'type': 'nsBMPEncoder',
+        'headers': ['/image/encoders/bmp/nsBMPEncoder.h'],
+    },
+    {
+        'cid': '{92ae3ab2-8968-41b1-8709-b6123bceaf21}',
+        'contract_ids': ['@mozilla.org/image/encoder;2?type=image/vnd.microsoft.icon'],
+        'type': 'nsICOEncoder',
+        'headers': ['/image/encoders/ico/nsICOEncoder.h'],
+    },
+    {
+        'cid': '{ac2bb8fe-eeeb-4572-b40f-be03932b56e0}',
+        'contract_ids': ['@mozilla.org/image/encoder;2?type=image/jpeg'],
+        'type': 'nsJPEGEncoder',
+        'headers': ['/image/encoders/jpeg/nsJPEGEncoder.h'],
+    },
+    {
+        'cid': '{38d1592e-b81e-432b-86f8-471878bbfe07}',
+        'contract_ids': ['@mozilla.org/image/encoder;2?type=image/png'],
+        'type': 'nsPNGEncoder',
+        'headers': ['/image/encoders/png/nsPNGEncoder.h'],
+    },
+]
--- a/image/build/moz.build
+++ b/image/build/moz.build
@@ -7,16 +7,20 @@
 EXPORTS += [
     'nsImageModule.h',
 ]
 
 SOURCES += [
     'nsImageModule.cpp',
 ]
 
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
+
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/image',
     '/image/encoders/bmp',
     '/image/encoders/ico',
     '/image/encoders/jpeg',
     '/image/encoders/png',
 ]
--- a/image/build/nsImageModule.cpp
+++ b/image/build/nsImageModule.cpp
@@ -2,142 +2,27 @@
  *
  * 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 "nsImageModule.h"
 
 #include "mozilla/ModuleUtils.h"
-#include "nsMimeTypes.h"
 
 #include "DecodePool.h"
 #include "ImageFactory.h"
 #include "ShutdownTracker.h"
 #include "SurfaceCache.h"
-#include "SurfacePipe.h"
 
 #include "gfxPrefs.h"
 #include "imgLoader.h"
-#include "imgRequest.h"
-#include "imgRequestProxy.h"
-#include "imgTools.h"
 
-#include "nsICOEncoder.h"
-#include "nsPNGEncoder.h"
-#include "nsJPEGEncoder.h"
-#include "nsBMPEncoder.h"
-
-// objects that just require generic constructors
 using namespace mozilla::image;
 
-// XXX We would like to get rid of the imgLoader factory constructor.  See the
-// comment documenting the imgLoader constructor.
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(imgLoader, Init)
-NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequestProxy)
-NS_GENERIC_FACTORY_CONSTRUCTOR(imgTools)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsICOEncoder)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsJPEGEncoder)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsPNGEncoder)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsBMPEncoder)
-NS_DEFINE_NAMED_CID(NS_IMGLOADER_CID);
-NS_DEFINE_NAMED_CID(NS_IMGREQUESTPROXY_CID);
-NS_DEFINE_NAMED_CID(NS_IMGTOOLS_CID);
-NS_DEFINE_NAMED_CID(NS_ICOENCODER_CID);
-NS_DEFINE_NAMED_CID(NS_JPEGENCODER_CID);
-NS_DEFINE_NAMED_CID(NS_PNGENCODER_CID);
-NS_DEFINE_NAMED_CID(NS_BMPENCODER_CID);
-
-static const mozilla::Module::CIDEntry kImageCIDs[] = {
-    {
-        &kNS_IMGLOADER_CID,
-        false,
-        nullptr,
-        imgLoaderConstructor,
-    },
-    {
-        &kNS_IMGREQUESTPROXY_CID,
-        false,
-        nullptr,
-        imgRequestProxyConstructor,
-    },
-    {
-        &kNS_IMGTOOLS_CID,
-        false,
-        nullptr,
-        imgToolsConstructor,
-    },
-    {
-        &kNS_ICOENCODER_CID,
-        false,
-        nullptr,
-        nsICOEncoderConstructor,
-    },
-    {
-        &kNS_JPEGENCODER_CID,
-        false,
-        nullptr,
-        nsJPEGEncoderConstructor,
-    },
-    {
-        &kNS_PNGENCODER_CID,
-        false,
-        nullptr,
-        nsPNGEncoderConstructor,
-    },
-    {
-        &kNS_BMPENCODER_CID,
-        false,
-        nullptr,
-        nsBMPEncoderConstructor,
-    },
-    {nullptr}};
-
-static const mozilla::Module::ContractIDEntry kImageContracts[] = {
-    {"@mozilla.org/image/cache;1", &kNS_IMGLOADER_CID},
-    {"@mozilla.org/image/loader;1", &kNS_IMGLOADER_CID},
-    {"@mozilla.org/image/request;1", &kNS_IMGREQUESTPROXY_CID},
-    {"@mozilla.org/image/tools;1", &kNS_IMGTOOLS_CID},
-    {"@mozilla.org/image/encoder;2?type=" IMAGE_ICO_MS, &kNS_ICOENCODER_CID},
-    {"@mozilla.org/image/encoder;2?type=" IMAGE_JPEG, &kNS_JPEGENCODER_CID},
-    {"@mozilla.org/image/encoder;2?type=" IMAGE_PNG, &kNS_PNGENCODER_CID},
-    {"@mozilla.org/image/encoder;2?type=" IMAGE_BMP, &kNS_BMPENCODER_CID},
-    {nullptr}};
-
-static const mozilla::Module::CategoryEntry kImageCategories[] = {
-    {"Gecko-Content-Viewers", IMAGE_GIF,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_JPEG,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_PJPEG,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_JPG,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_ICO,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_ICO_MS,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_BMP,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_BMP_MS,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_ICON_MS,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_PNG,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_APNG,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_X_PNG,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"Gecko-Content-Viewers", IMAGE_WEBP,
-     "@mozilla.org/content/document-loader-factory;1"},
-    {"content-sniffing-services", "@mozilla.org/image/loader;1",
-     "@mozilla.org/image/loader;1"},
-    {nullptr}};
-
 static bool sInitialized = false;
 nsresult mozilla::image::EnsureModuleInitialized() {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (sInitialized) {
     return NS_OK;
   }
 
@@ -156,19 +41,8 @@ nsresult mozilla::image::EnsureModuleIni
 void mozilla::image::ShutdownModule() {
   if (!sInitialized) {
     return;
   }
   imgLoader::Shutdown();
   mozilla::image::SurfaceCache::Shutdown();
   sInitialized = false;
 }
-
-static const mozilla::Module kImageModule = {
-    mozilla::Module::kVersion, kImageCIDs, kImageContracts, kImageCategories,
-    nullptr, mozilla::image::EnsureModuleInitialized,
-    // We need to be careful about shutdown ordering to avoid intermittent
-    // crashes when hashtable enumeration decides to destroy modules in an
-    // unfortunate order. So our shutdown is invoked explicitly during layout
-    // module shutdown.
-    nullptr};
-
-NSMODULE_DEFN(nsImageLib2Module) = &kImageModule;
new file mode 100644
--- /dev/null
+++ b/image/decoders/icon/components.conf
@@ -0,0 +1,19 @@
+# -*- 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': '{d0f9db12-249c-11d5-9905-001083010e9b}',
+        'contract_ids': ['@mozilla.org/network/protocol;1?name=moz-icon'],
+        'type': 'nsIconProtocolHandler',
+        'headers': ['/image/decoders/icon/nsIconProtocolHandler.h'],
+    },
+    {
+        'cid': '{1460df3b-774c-4205-8349-838e507c3ef9}',
+        'type': 'nsMozIconURI::Mutator',
+        'headers': ['/image/decoders/icon/nsIconURI.h'],
+    },
+]
--- a/image/decoders/icon/moz.build
+++ b/image/decoders/icon/moz.build
@@ -1,20 +1,23 @@
 # -*- 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/.
 
 UNIFIED_SOURCES += [
-    'nsIconModule.cpp',
     'nsIconProtocolHandler.cpp',
     'nsIconURI.cpp',
 ]
 
+XPCOM_MANIFESTS += [
+    'components.conf',
+]
+
 FINAL_LIBRARY = 'xul'
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 platform = None
 
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     platform = 'gtk'
deleted file mode 100644
--- a/image/decoders/icon/nsIconModule.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/ModuleUtils.h"
-#include "nsServiceManagerUtils.h"
-
-#include "nsIconProtocolHandler.h"
-#include "nsIconURI.h"
-#include "nsIconChannel.h"
-
-// objects that just require generic constructors
-//*****************************************************************************
-// Protocol CIDs
-
-#define NS_ICONPROTOCOL_CID                                                    \
-  {                                                                            \
-    0xd0f9db12, 0x249c, 0x11d5, { 0x99, 0x5, 0x0, 0x10, 0x83, 0x1, 0xe, 0x9b } \
-  }
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsIconProtocolHandler)
-typedef nsMozIconURI::Mutator nsMozIconURIMutator;
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsMozIconURIMutator)
-
-NS_DEFINE_NAMED_CID(NS_ICONPROTOCOL_CID);
-NS_DEFINE_NAMED_CID(NS_MOZICONURIMUTATOR_CID);
-
-static const mozilla::Module::CIDEntry kIconCIDs[] = {
-    {&kNS_ICONPROTOCOL_CID, false, nullptr, nsIconProtocolHandlerConstructor},
-    {&kNS_MOZICONURIMUTATOR_CID, false, nullptr,
-     nsMozIconURIMutatorConstructor},
-    {nullptr}};
-
-static const mozilla::Module::ContractIDEntry kIconContracts[] = {
-    {NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "moz-icon", &kNS_ICONPROTOCOL_CID},
-    {nullptr}};
-
-static const mozilla::Module::CategoryEntry kIconCategories[] = {{nullptr}};
-
-static void IconDecoderModuleDtor() {}
-
-static const mozilla::Module kIconModule = {
-    mozilla::Module::kVersion, kIconCIDs, kIconContracts,
-    kIconCategories,           nullptr,   nullptr,
-    IconDecoderModuleDtor};
-
-NSMODULE_DEFN(nsIconDecoderModule) = &kIconModule;
--- a/image/imgIContainer.idl
+++ b/image/imgIContainer.idl
@@ -138,16 +138,21 @@ interface imgIContainer : nsISupports
    * Whether this image is animated. You can only be guaranteed that querying
    * this will not throw if STATUS_DECODE_COMPLETE is set on the imgIRequest.
    *
    * @throws NS_ERROR_NOT_AVAILABLE if the animated state cannot be determined.
    */
   readonly attribute boolean animated;
 
   /**
+   * Producer ID for image containers created by this image.
+   */
+  [infallible] readonly attribute unsigned long producerId;
+
+  /**
    * Flags for imgIContainer operations.
    *
    * Meanings:
    *
    * FLAG_NONE: Lack of flags.
    *
    * FLAG_SYNC_DECODE: Forces synchronous/non-progressive decode of all
    * available data before the call returns.
--- a/image/imgIRequest.idl
+++ b/image/imgIRequest.idl
@@ -25,16 +25,21 @@ interface imgIRequest : nsIRequest
   /**
    * the image container...
    * @return the image object associated with the request.
    * @attention NEED DOCS
    */
   readonly attribute imgIContainer image;
 
   /**
+   * Producer ID for image containers created by this image.
+   */
+  [infallible] readonly attribute unsigned long producerId;
+
+  /**
    * Bits set in the return value from imageStatus
    * @name statusflags
    *
    * Meanings:
    *
    * STATUS_NONE: Nothing to report.
    *
    * STATUS_SIZE_AVAILABLE: We received enough image data
--- a/image/imgRequestProxy.cpp
+++ b/image/imgRequestProxy.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "imgRequestProxy.h"
 
 #include "ImageLogging.h"
 #include "imgLoader.h"
 #include "Image.h"
 #include "ImageOps.h"
+#include "ImageTypes.h"
 #include "nsError.h"
 #include "nsCRTGlue.h"
 #include "imgINotificationObserver.h"
 #include "mozilla/dom/TabGroup.h"  // for TabGroup
 #include "mozilla/dom/DocGroup.h"  // for DocGroup
 #include "mozilla/Move.h"
 #include "mozilla/Telemetry.h"  // for Telemetry
 
@@ -658,16 +659,31 @@ imgRequestProxy::GetImage(imgIContainer*
   }
 
   imageToReturn.swap(*aImage);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+imgRequestProxy::GetProducerId(uint32_t* aId) {
+  NS_ENSURE_TRUE(aId, NS_ERROR_NULL_POINTER);
+
+  nsCOMPtr<imgIContainer> image;
+  nsresult rv = GetImage(getter_AddRefs(image));
+  if (NS_SUCCEEDED(rv)) {
+    *aId = image->GetProducerId();
+  } else {