Merge mozilla-inbound to mozilla-central a=merge
authorRazvan Maries <rmaries@mozilla.com>
Mon, 28 Jan 2019 23:46:39 +0200
changeset 513550 d305772af471
parent 513522 5f877600f76f (current diff)
parent 513549 60a092e58104 (diff)
child 513556 f039f8426b5f
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
d305772af471 / 67.0a1 / 20190128214724 / files
nightly linux64
d305772af471 / 67.0a1 / 20190128214724 / files
nightly mac
d305772af471 / 67.0a1 / 20190128214724 / files
nightly win32
d305772af471 / 67.0a1 / 20190128214724 / files
nightly win64
d305772af471 / 67.0a1 / 20190128214724 / 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
dom/base/nsGlobalWindowOuter.cpp
testing/web-platform/meta/css/CSS2/backgrounds/background-root-010.xht.ini
testing/web-platform/meta/css/CSS2/backgrounds/background-root-016.xht.ini
--- a/browser/base/content/test/trackingUI/browser_trackingUI_animation.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_animation.js
@@ -2,39 +2,44 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html";
 const TP_PREF = "privacy.trackingprotection.enabled";
 const ANIMATIONS_PREF = "toolkit.cosmeticAnimations.enabled";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 
 // Test that the shield icon animation can be controlled by the cosmetic
 // animations pref and that one of the icons is visible in each case.
 add_task(async function testShieldAnimation() {
   await UrlClassifierTestUtils.addTestTrackers();
   Services.prefs.setBoolPref(TP_PREF, true);
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
 
   let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
 
   let animationIcon = document.getElementById("tracking-protection-icon-animatable-image");
   let noAnimationIcon = document.getElementById("tracking-protection-icon");
 
   Services.prefs.setBoolPref(ANIMATIONS_PREF, true);
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.linkedBrowser.ownerGlobal)]);
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden when animations are enabled");
   ok(BrowserTestUtils.is_visible(animationIcon), "the animated icon is shown when animations are enabled");
 
   await promiseTabLoadEvent(tab, BENIGN_PAGE);
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden");
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden");
 
   Services.prefs.setBoolPref(ANIMATIONS_PREF, false);
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.linkedBrowser.ownerGlobal)]);
   ok(BrowserTestUtils.is_visible(noAnimationIcon), "the default icon is shown when animations are disabled");
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden when animations are disabled");
 
   gBrowser.removeCurrentTab();
   Services.prefs.clearUserPref(ANIMATIONS_PREF);
   Services.prefs.clearUserPref(TP_PREF);
+  Services.prefs.clearUserPref(DTSCBN_PREF);
   UrlClassifierTestUtils.cleanupTestTrackers();
 });
--- a/browser/base/content/test/trackingUI/browser_trackingUI_animation_2.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_animation_2.js
@@ -6,28 +6,32 @@
  */
 
 const TP_PREF = "privacy.trackingprotection.enabled";
 const TP_PB_PREF = "privacy.trackingprotection.enabled";
 const NCB_PREF = "network.cookie.cookieBehavior";
 const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html";
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const COOKIE_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/cookiePage.html";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 
 requestLongerTimeout(2);
 
 registerCleanupFunction(function() {
   UrlClassifierTestUtils.cleanupTestTrackers();
   Services.prefs.clearUserPref(TP_PREF);
   Services.prefs.clearUserPref(TP_PB_PREF);
   Services.prefs.clearUserPref(NCB_PREF);
+  Services.prefs.clearUserPref(DTSCBN_PREF);
   Services.prefs.clearUserPref(ContentBlocking.prefIntroCount);
 });
 
 async function testTrackingProtectionAnimation(tabbrowser) {
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
+
   info("Load a test page not containing tracking elements");
   let benignTab = await BrowserTestUtils.openNewForegroundTab(tabbrowser, BENIGN_PAGE);
   let ContentBlocking = tabbrowser.ownerGlobal.ContentBlocking;
 
   ok(!ContentBlocking.iconBox.hasAttribute("active"), "iconBox not active");
   ok(!ContentBlocking.iconBox.hasAttribute("animate"), "iconBox not animating");
 
   info("Load a test page containing tracking elements");
--- a/browser/base/content/test/trackingUI/browser_trackingUI_pbmode_exceptions.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_pbmode_exceptions.js
@@ -1,22 +1,24 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that sites added to the Tracking Protection whitelist in private
 // browsing mode don't persist once the private browsing window closes.
 
 const TP_PB_PREF = "privacy.trackingprotection.enabled";
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 var TrackingProtection = null;
 var ContentBlocking = null;
 var browser = null;
 
 registerCleanupFunction(function() {
   Services.prefs.clearUserPref(TP_PB_PREF);
+  Services.prefs.clearUserPref(DTSCBN_PREF);
   ContentBlocking = TrackingProtection = browser = null;
   UrlClassifierTestUtils.cleanupTestTrackers();
 });
 
 function hidden(sel) {
   let win = browser.ownerGlobal;
   let el = win.document.querySelector(sel);
   let display = win.getComputedStyle(el).getPropertyValue("display", null);
@@ -74,30 +76,32 @@ function testTrackingPageUnblocked() {
   ok(hidden("#tracking-action-unblock"), "unblockButton is hidden");
 
   ok(hidden("#identity-popup-content-blocking-not-detected"), "blocking not detected label is hidden");
   ok(!hidden("#identity-popup-content-blocking-detected"), "blocking detected label is visible");
 }
 
 add_task(async function testExceptionAddition() {
   await UrlClassifierTestUtils.addTestTrackers();
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
   let privateWin = await BrowserTestUtils.openNewBrowserWindow({private: true});
   browser = privateWin.gBrowser;
   let tab = await BrowserTestUtils.openNewForegroundTab({ gBrowser: browser, waitForLoad: true, waitForStateStop: true });
 
   ContentBlocking = browser.ownerGlobal.ContentBlocking;
   ok(ContentBlocking, "CB is attached to the private window");
   TrackingProtection = browser.ownerGlobal.TrackingProtection;
   ok(TrackingProtection, "TP is attached to the private window");
 
   Services.prefs.setBoolPref(TP_PB_PREF, true);
   ok(TrackingProtection.enabled, "TP is enabled after setting the pref");
 
   info("Load a test page containing tracking elements");
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
 
   testTrackingPage(tab.ownerGlobal);
 
   info("Disable TP for the page (which reloads the page)");
   let tabReloadPromise = promiseTabLoadEvent(tab);
   clickButton("#tracking-action-unblock");
   is(identityPopupState(), "closed", "Identity popup is closed");
 
@@ -123,22 +127,24 @@ add_task(async function testExceptionPer
   ContentBlocking = browser.ownerGlobal.ContentBlocking;
   ok(ContentBlocking, "CB is attached to the private window");
   TrackingProtection = browser.ownerGlobal.TrackingProtection;
   ok(TrackingProtection, "TP is attached to the private window");
 
   ok(TrackingProtection.enabled, "TP is still enabled");
 
   info("Load a test page containing tracking elements");
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
 
   testTrackingPage(tab.ownerGlobal);
 
   info("Disable TP for the page (which reloads the page)");
   let tabReloadPromise = promiseTabLoadEvent(tab);
   clickButton("#tracking-action-unblock");
   is(identityPopupState(), "closed", "Identity popup is closed");
 
-  await tabReloadPromise;
+  await Promise.all([tabReloadPromise,
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
   testTrackingPageUnblocked();
 
   privateWin.close();
 });
--- a/browser/base/content/test/trackingUI/browser_trackingUI_state.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_state.js
@@ -12,32 +12,34 @@
  *     2) A page with tracking elements is loaded.
  *
  * See also Bugs 1175327, 1043801, 1178985
  */
 
 const TP_PREF = "privacy.trackingprotection.enabled";
 const TP_PB_PREF = "privacy.trackingprotection.pbmode.enabled";
 const TPC_PREF = "network.cookie.cookieBehavior";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html";
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const COOKIE_PAGE = "http://not-tracking.example.com/browser/browser/base/content/test/trackingUI/cookiePage.html";
 var ContentBlocking = null;
 var TrackingProtection = null;
 var ThirdPartyCookies = null;
 var tabbrowser = null;
 var gTrackingPageURL = TRACKING_PAGE;
 
 registerCleanupFunction(function() {
   TrackingProtection = ContentBlocking =
     ThirdPartyCookies = tabbrowser = null;
   UrlClassifierTestUtils.cleanupTestTrackers();
   Services.prefs.clearUserPref(TP_PREF);
   Services.prefs.clearUserPref(TP_PB_PREF);
   Services.prefs.clearUserPref(TPC_PREF);
+  Services.prefs.clearUserPref(DTSCBN_PREF);
 });
 
 // This is a special version of "hidden" that doesn't check for item
 // visibility and just asserts the display and opacity attributes.
 // That way we can test elements even when their panel is hidden...
 function hidden(sel) {
   let win = tabbrowser.ownerGlobal;
   let el = win.document.querySelector(sel);
@@ -101,30 +103,29 @@ function areTrackersBlocked(isPrivateBro
   return blockedByTP || blockedByTPC;
 }
 
 function testTrackingPage(window) {
   info("Tracking content must be blocked");
   ok(ContentBlocking.content.hasAttribute("detected"), "trackers are detected");
   ok(!ContentBlocking.content.hasAttribute("hasException"), "content shows no exception");
 
-  let isPrivateBrowsing = PrivateBrowsingUtils.isWindowPrivate(window);
-  let blockedByTP = areTrackersBlocked(isPrivateBrowsing);
+  let isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
+  let blockedByTP = areTrackersBlocked(isWindowPrivate);
   is(BrowserTestUtils.is_visible(ContentBlocking.iconBox), blockedByTP,
      "icon box is" + (blockedByTP ? "" : " not") + " visible");
   is(ContentBlocking.iconBox.hasAttribute("active"), blockedByTP,
       "shield is" + (blockedByTP ? "" : " not") + " active");
   ok(!ContentBlocking.iconBox.hasAttribute("hasException"), "icon box shows no exception");
   is(ContentBlocking.iconBox.getAttribute("tooltiptext"),
      blockedByTP ? gNavigatorBundle.getString("trackingProtection.icon.activeTooltip") : "",
      "correct tooltip");
 
   ok(hidden("#tracking-action-block"), "blockButton is hidden");
 
-  let isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
   if (isWindowPrivate) {
     ok(hidden("#tracking-action-unblock"), "unblockButton is hidden");
     is(!hidden("#tracking-action-unblock-private"), blockedByTP,
        "unblockButtonPrivate is" + (blockedByTP ? "" : " not") + " visible");
   } else {
     ok(hidden("#tracking-action-unblock-private"), "unblockButtonPrivate is hidden");
     is(!hidden("#tracking-action-unblock"), blockedByTP,
        "unblockButton is" + (blockedByTP ? "" : " not") + " visible");
@@ -213,16 +214,18 @@ async function testContentBlocking(tab) 
   clickButton("#tracking-action-block");
   await tabReloadPromise;
   testTrackingPage(tab.ownerGlobal);
 }
 
 add_task(async function testNormalBrowsing() {
   await UrlClassifierTestUtils.addTestTrackers();
 
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
+
   tabbrowser = gBrowser;
   let tab = tabbrowser.selectedTab = BrowserTestUtils.addTab(tabbrowser);
 
   ContentBlocking = gBrowser.ownerGlobal.ContentBlocking;
   ok(ContentBlocking, "CB is attached to the browser window");
   TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
   ok(TrackingProtection, "TP is attached to the browser window");
   is(TrackingProtection.enabled, Services.prefs.getBoolPref(TP_PREF),
--- a/browser/base/content/test/trackingUI/browser_trackingUI_state_all_disabled.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_state_all_disabled.js
@@ -3,50 +3,54 @@
 
 "use strict";
 
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html";
 const TP_PREF = "privacy.trackingprotection.enabled";
 const COOKIE_PREF = "network.cookie.cookieBehavior";
 const ANIMATIONS_PREF = "toolkit.cosmeticAnimations.enabled";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 
 // Check that the shield icon is always hidden when all content blocking
 // categories are turned off, even when content blocking is on.
 add_task(async function testContentBlockingAllDisabled() {
   await SpecialPowers.pushPrefEnv({set: [
     [TP_PREF, false],
     [COOKIE_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT],
+    [DTSCBN_PREF, true],
   ]});
   await UrlClassifierTestUtils.addTestTrackers();
 
   let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   Services.prefs.setBoolPref(ANIMATIONS_PREF, true);
 
   registerCleanupFunction(function() {
     gBrowser.removeCurrentTab();
     Services.prefs.clearUserPref(ANIMATIONS_PREF);
     UrlClassifierTestUtils.cleanupTestTrackers();
   });
 
   let animationIcon = document.getElementById("tracking-protection-icon-animatable-image");
   let noAnimationIcon = document.getElementById("tracking-protection-icon");
 
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden");
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden");
 
   await promiseTabLoadEvent(tab, BENIGN_PAGE);
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden");
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden");
 
   Services.prefs.setBoolPref(ANIMATIONS_PREF, false);
   await promiseTabLoadEvent(tab, TRACKING_PAGE);
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden");
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden");
 
   // Sanitity check that the shield is showing when at least one blocker is enabled.
   await SpecialPowers.pushPrefEnv({set: [
     [TP_PREF, true],
   ]});
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
   ok(BrowserTestUtils.is_visible(noAnimationIcon), "the default icon is shown");
 });
--- a/browser/base/content/test/trackingUI/browser_trackingUI_telemetry.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_telemetry.js
@@ -1,37 +1,40 @@
 /*
  * Test telemetry for Tracking Protection
  */
 
 const PREF = "privacy.trackingprotection.enabled";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html";
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 
 /**
  * Enable local telemetry recording for the duration of the tests.
  */
 var oldCanRecord = Services.telemetry.canRecordExtended;
 Services.telemetry.canRecordExtended = true;
 registerCleanupFunction(function() {
   UrlClassifierTestUtils.cleanupTestTrackers();
   Services.telemetry.canRecordExtended = oldCanRecord;
   Services.prefs.clearUserPref(PREF);
+  Services.prefs.clearUserPref(DTSCBN_PREF);
 });
 
 function getShieldHistogram() {
   return Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD");
 }
 
 function getShieldCounts() {
   return getShieldHistogram().snapshot().values;
 }
 
 add_task(async function setup() {
   await UrlClassifierTestUtils.addTestTrackers();
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
 
   let TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
   ok(TrackingProtection, "TP is attached to the browser window");
   ok(!TrackingProtection.enabled, "TP is not enabled");
 
   let enabledCounts =
     Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED").snapshot().values;
   is(enabledCounts[0], 1, "TP was not enabled on start up");
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -83,17 +83,17 @@ skip-if = os == "linux" # Intermittent f
 [browser_947914_button_zoomReset.js]
 skip-if = os == "linux" # Intermittent failures
 [browser_947987_removable_default.js]
 [browser_948985_non_removable_defaultArea.js]
 [browser_952963_areaType_getter_no_area.js]
 skip-if = verify
 [browser_956602_remove_special_widget.js]
 [browser_962069_drag_to_overflow_chevron.js]
-skip-if = verify
+skip-if = verify || os == "linux" || os == "mac" && debug # bug 1515204
 [browser_963639_customizing_attribute_non_customizable_toolbar.js]
 [browser_967000_button_charEncoding.js]
 [browser_968565_insert_before_hidden_items.js]
 [browser_969427_recreate_destroyed_widget_after_reset.js]
 [browser_969661_character_encoding_navbar_disabled.js]
 [browser_970511_undo_restore_default.js]
 skip-if = verify
 [browser_972267_customizationchange_events.js]
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 2.1.215
+Current extension version is: 2.1.228
 
-Taken from upstream commit: 9128335c
+Taken from upstream commit: 1f3e7700
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.1.215';
-var pdfjsBuild = '9128335c';
+var pdfjsVersion = '2.1.228';
+var pdfjsBuild = '1f3e7700';
 
 var pdfjsSharedUtil = __w_pdfjs_require__(1);
 
 var pdfjsDisplayAPI = __w_pdfjs_require__(6);
 
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(18);
 
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(19);
@@ -1392,17 +1392,17 @@ function _fetchDocument(worker, source, 
 
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
   }
 
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
     docId,
-    apiVersion: '2.1.215',
+    apiVersion: '2.1.228',
     source: {
       data: source.data,
       url: source.url,
       password: source.password,
       disableAutoFetch: source.disableAutoFetch,
       rangeChunkSize: source.rangeChunkSize,
       length: source.length
     },
@@ -3037,29 +3037,29 @@ const InternalRenderTask = function Inte
       this.operatorListIdx = 0;
       this.graphicsReady = true;
 
       if (this.graphicsReadyCallback) {
         this.graphicsReadyCallback();
       }
     }
 
-    cancel() {
+    cancel(error = null) {
       this.running = false;
       this.cancelled = true;
 
       if (this.gfx) {
         this.gfx.endDrawing();
       }
 
       if (this._canvas) {
         canvasInRendering.delete(this._canvas);
       }
 
-      this.callback(new _dom_utils.RenderingCancelledException('Rendering cancelled, page ' + this.pageNumber, 'canvas'));
+      this.callback(error || new _dom_utils.RenderingCancelledException(`Rendering cancelled, page ${this.pageNumber}`, 'canvas'));
     }
 
     operatorListChanged() {
       if (!this.graphicsReady) {
         if (!this.graphicsReadyCallback) {
           this.graphicsReadyCallback = this._continueBound;
         }
 
@@ -3089,20 +3089,20 @@ const InternalRenderTask = function Inte
       } else {
         this._scheduleNext();
       }
     }
 
     _scheduleNext() {
       if (this._useRequestAnimationFrame) {
         window.requestAnimationFrame(() => {
-          this._nextBound().catch(this.callback);
+          this._nextBound().catch(this.cancel.bind(this));
         });
       } else {
-        Promise.resolve().then(this._nextBound).catch(this.callback);
+        Promise.resolve().then(this._nextBound).catch(this.cancel.bind(this));
       }
     }
 
     async _next() {
       if (this.cancelled) {
         return;
       }
 
@@ -3123,19 +3123,19 @@ const InternalRenderTask = function Inte
       }
     }
 
   }
 
   return InternalRenderTask;
 }();
 
-const version = '2.1.215';
+const version = '2.1.228';
 exports.version = version;
-const build = '9128335c';
+const build = '1f3e7700';
 exports.build = build;
 
 /***/ }),
 /* 7 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-const pdfjsVersion = '2.1.215';
-const pdfjsBuild = '9128335c';
+const pdfjsVersion = '2.1.228';
+const pdfjsBuild = '1f3e7700';
 
 const pdfjsCoreWorker = __w_pdfjs_require__(1);
 
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
@@ -370,17 +370,17 @@ var WorkerMessageHandler = {
   },
 
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.1.215';
+    let workerVersion = '2.1.228';
 
     if (apiVersion !== workerVersion) {
       throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
     }
 
     var docId = docParams.docId;
     var docBaseUrl = docParams.docBaseUrl;
     var workerHandlerName = docParams.docId + '_worker';
@@ -4519,20 +4519,23 @@ var XRef = function XRefClosure() {
         var token = readToken(buffer, position);
         var m;
 
         if (token.startsWith('xref') && (token.length === 4 || /\s/.test(token[4]))) {
           position += skipUntil(buffer, position, trailerBytes);
           trailers.push(position);
           position += skipUntil(buffer, position, startxrefBytes);
         } else if (m = objRegExp.exec(token)) {
-          if (typeof this.entries[m[1]] === 'undefined') {
-            this.entries[m[1]] = {
+          const num = m[1] | 0,
+                gen = m[2] | 0;
+
+          if (typeof this.entries[num] === 'undefined') {
+            this.entries[num] = {
               offset: position - stream.start,
-              gen: m[2] | 0,
+              gen,
               uncompressed: true
             };
           }
 
           let contentLength,
               startPos = position + token.length;
 
           while (startPos < buffer.length) {
@@ -16888,16 +16891,20 @@ class ColorSpace {
   getOutputLength(inputLength, alpha01) {
     (0, _util.unreachable)('Should not call ColorSpace.getOutputLength');
   }
 
   isPassthrough(bits) {
     return false;
   }
 
+  isDefaultDecode(decodeMap, bpc) {
+    return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+  }
+
   fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) {
     let count = originalWidth * originalHeight;
     let rgbBuf = null;
     let numComponentColors = 1 << bpc;
     let needsResizing = originalHeight !== height || originalWidth !== width;
 
     if (this.isPassthrough(bpc)) {
       rgbBuf = comps;
@@ -17166,22 +17173,22 @@ class ColorSpace {
         default:
           throw new _util.FormatError(`unimplemented color space object "${mode}"`);
       }
     }
 
     throw new _util.FormatError(`unrecognized color space object: "${cs}"`);
   }
 
-  static isDefaultDecode(decode, n) {
+  static isDefaultDecode(decode, numComps) {
     if (!Array.isArray(decode)) {
       return true;
     }
 
-    if (n * 2 !== decode.length) {
+    if (numComps * 2 !== decode.length) {
       (0, _util.warn)('The decode map is not the correct length');
       return true;
     }
 
     for (let i = 0, ii = decode.length; i < ii; i += 2) {
       if (decode[i] !== 0 || decode[i + 1] !== 1) {
         return false;
       }
@@ -17260,28 +17267,28 @@ class AlternateCS extends ColorSpace {
       base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
     }
   }
 
   getOutputLength(inputLength, alpha01) {
     return this.base.getOutputLength(inputLength * this.base.numComps / this.numComps, alpha01);
   }
 
-  isDefaultDecode(decodeMap) {
-    return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-  }
-
 }
 
 class PatternCS extends ColorSpace {
   constructor(baseCS) {
     super('Pattern', null);
     this.base = baseCS;
   }
 
+  isDefaultDecode(decodeMap, bpc) {
+    (0, _util.unreachable)('Should not call PatternCS.isDefaultDecode');
+  }
+
 }
 
 class IndexedCS extends ColorSpace {
   constructor(base, highVal, lookup) {
     super('Indexed', 1);
     this.base = base;
     this.highVal = highVal;
     let baseNumComps = base.numComps;
@@ -17322,18 +17329,32 @@ class IndexedCS extends ColorSpace {
       destOffset += outputDelta;
     }
   }
 
   getOutputLength(inputLength, alpha01) {
     return this.base.getOutputLength(inputLength * this.base.numComps, alpha01);
   }
 
-  isDefaultDecode(decodeMap) {
-    return true;
+  isDefaultDecode(decodeMap, bpc) {
+    if (!Array.isArray(decodeMap)) {
+      return true;
+    }
+
+    if (decodeMap.length !== 2) {
+      (0, _util.warn)('Decode map length is not correct');
+      return true;
+    }
+
+    if (!Number.isInteger(bpc) || bpc < 1) {
+      (0, _util.warn)('Bits per component is not correct');
+      return true;
+    }
+
+    return decodeMap[0] === 0 && decodeMap[1] === (1 << bpc) - 1;
   }
 
 }
 
 class DeviceGrayCS extends ColorSpace {
   constructor() {
     super('DeviceGray', 1);
   }
@@ -17356,20 +17377,16 @@ class DeviceGrayCS extends ColorSpace {
       q += alpha01;
     }
   }
 
   getOutputLength(inputLength, alpha01) {
     return inputLength * (3 + alpha01);
   }
 
-  isDefaultDecode(decodeMap) {
-    return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-  }
-
 }
 
 class DeviceRgbCS extends ColorSpace {
   constructor() {
     super('DeviceRGB', 3);
   }
 
   getRgbItem(src, srcOffset, dest, destOffset) {
@@ -17399,20 +17416,16 @@ class DeviceRgbCS extends ColorSpace {
   getOutputLength(inputLength, alpha01) {
     return inputLength * (3 + alpha01) / 3 | 0;
   }
 
   isPassthrough(bits) {
     return bits === 8;
   }
 
-  isDefaultDecode(decodeMap) {
-    return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-  }
-
 }
 
 const DeviceCmykCS = function DeviceCmykCSClosure() {
   function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
     let c = src[srcOffset] * srcScale;
     let m = src[srcOffset + 1] * srcScale;
     let y = src[srcOffset + 2] * srcScale;
     let k = src[srcOffset + 3] * srcScale;
@@ -17439,20 +17452,16 @@ const DeviceCmykCS = function DeviceCmyk
         destOffset += 3 + alpha01;
       }
     }
 
     getOutputLength(inputLength, alpha01) {
       return inputLength / 4 * (3 + alpha01) | 0;
     }
 
-    isDefaultDecode(decodeMap) {
-      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-    }
-
   }
 
   return DeviceCmykCS;
 }();
 
 const CalGrayCS = function CalGrayCSClosure() {
   function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
     let A = src[srcOffset] * scale;
@@ -17514,20 +17523,16 @@ const CalGrayCS = function CalGrayCSClos
         destOffset += 3 + alpha01;
       }
     }
 
     getOutputLength(inputLength, alpha01) {
       return inputLength * (3 + alpha01);
     }
 
-    isDefaultDecode(decodeMap) {
-      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-    }
-
   }
 
   return CalGrayCS;
 }();
 
 const CalRGBCS = function CalRGBCSClosure() {
   const BRADFORD_SCALE_MATRIX = new Float32Array([0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296]);
   const BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([0.9869929, -0.1470543, 0.1599627, 0.4323053, 0.5183603, 0.0492912, -0.0085287, 0.0400428, 0.9684867]);
@@ -17719,20 +17724,16 @@ const CalRGBCS = function CalRGBCSClosur
         destOffset += 3 + alpha01;
       }
     }
 
     getOutputLength(inputLength, alpha01) {
       return inputLength * (3 + alpha01) / 3 | 0;
     }
 
-    isDefaultDecode(decodeMap) {
-      return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
-    }
-
   }
 
   return CalRGBCS;
 }();
 
 const LabCS = function LabCSClosure() {
   function fn_g(x) {
     let result;
@@ -17838,17 +17839,17 @@ const LabCS = function LabCSClosure() {
         destOffset += 3 + alpha01;
       }
     }
 
     getOutputLength(inputLength, alpha01) {
       return inputLength * (3 + alpha01) / 3 | 0;
     }
 
-    isDefaultDecode(decodeMap) {
+    isDefaultDecode(decodeMap, bpc) {
       return true;
     }
 
     get usesZeroToOneRange() {
       return (0, _util.shadow)(this, 'usesZeroToOneRange', false);
     }
 
   }
@@ -19549,17 +19550,18 @@ var PartialEvaluator = function PartialE
     var dict = image.dict;
 
     if (dict.has('DecodeParms') || dict.has('DP')) {
       return false;
     }
 
     var cs = _colorspace.ColorSpace.parse(dict.get('ColorSpace', 'CS'), xref, res, pdfFunctionFactory);
 
-    return (cs.numComps === 1 || cs.numComps === 3) && cs.isDefaultDecode(dict.getArray('Decode', 'D'));
+    const bpc = dict.get('BitsPerComponent', 'BPC') || 1;
+    return (cs.numComps === 1 || cs.numComps === 3) && cs.isDefaultDecode(dict.getArray('Decode', 'D'), bpc);
   };
 
   function PartialEvaluator({
     pdfManager,
     xref,
     handler,
     pageIndex,
     idFactory,
@@ -43574,27 +43576,28 @@ var PDFImage = function PDFImageClosure(
       let resources = isInline ? res : null;
       this.colorSpace = _colorspace.ColorSpace.parse(colorSpace, xref, resources, pdfFunctionFactory);
       this.numComps = this.colorSpace.numComps;
     }
 
     this.decode = dict.getArray('Decode', 'D');
     this.needsDecode = false;
 
-    if (this.decode && (this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode) || isMask && !_colorspace.ColorSpace.isDefaultDecode(this.decode, 1))) {
+    if (this.decode && (this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode, bitsPerComponent) || isMask && !_colorspace.ColorSpace.isDefaultDecode(this.decode, 1))) {
       this.needsDecode = true;
       var max = (1 << bitsPerComponent) - 1;
       this.decodeCoefficients = [];
       this.decodeAddends = [];
+      const isIndexed = this.colorSpace && this.colorSpace.name === 'Indexed';
 
       for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
         var dmin = this.decode[i];
         var dmax = this.decode[i + 1];
-        this.decodeCoefficients[j] = dmax - dmin;
-        this.decodeAddends[j] = max * dmin;
+        this.decodeCoefficients[j] = isIndexed ? (dmax - dmin) / max : dmax - dmin;
+        this.decodeAddends[j] = isIndexed ? dmin : max * dmin;
       }
     }
 
     if (smask) {
       this.smask = new PDFImage({
         xref,
         res,
         image: smask,
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -2662,17 +2662,17 @@ function getVisibleElements(scrollEl, vi
     const elementRight = element.offsetLeft + element.clientLeft + element.clientWidth;
     return elementRight > left;
   }
 
   const visible = [],
         numViews = views.length;
   let firstVisibleElementInd = numViews === 0 ? 0 : binarySearchFirstItem(views, horizontal ? isElementRightAfterViewLeft : isElementBottomAfterViewTop);
 
-  if (numViews > 0 && firstVisibleElementInd < numViews && !horizontal) {
+  if (firstVisibleElementInd > 0 && firstVisibleElementInd < numViews && !horizontal) {
     firstVisibleElementInd = backtrackBeforeAllVisibleElements(firstVisibleElementInd, views, top);
   }
 
   let lastEdge = horizontal ? right : -1;
 
   for (let i = firstVisibleElementInd; i < numViews; i++) {
     const view = views[i],
           element = view.div;
@@ -8123,54 +8123,57 @@ exports.PDFThumbnailView = PDFThumbnailV
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.PDFViewer = void 0;
 
 var _base_viewer = __webpack_require__(25);
 
-var _ui_utils = __webpack_require__(2);
-
 var _pdfjsLib = __webpack_require__(3);
 
 class PDFViewer extends _base_viewer.BaseViewer {
   get _setDocumentViewerElement() {
     return (0, _pdfjsLib.shadow)(this, '_setDocumentViewerElement', this.viewer);
   }
 
   _scrollIntoView({
     pageDiv,
-    pageSpot = null
+    pageSpot = null,
+    pageNumber = null
   }) {
     if (!pageSpot && !this.isInPresentationMode) {
       const left = pageDiv.offsetLeft + pageDiv.clientLeft;
       const right = left + pageDiv.clientWidth;
       const {
         scrollLeft,
         clientWidth
       } = this.container;
 
-      if (this._scrollMode === _base_viewer.ScrollMode.HORIZONTAL || left < scrollLeft || right > scrollLeft + clientWidth) {
+      if (this._isScrollModeHorizontal || left < scrollLeft || right > scrollLeft + clientWidth) {
         pageSpot = {
           left: 0,
           top: 0
         };
       }
     }
 
-    (0, _ui_utils.scrollIntoView)(pageDiv, pageSpot);
+    super._scrollIntoView({
+      pageDiv,
+      pageSpot,
+      pageNumber
+    });
   }
 
   _getVisiblePages() {
-    if (!this.isInPresentationMode) {
-      return (0, _ui_utils.getVisibleElements)(this.container, this._pages, true, this._scrollMode === _base_viewer.ScrollMode.HORIZONTAL);
-    }
-
-    return this._getCurrentVisiblePage();
+    if (this.isInPresentationMode) {
+      return this._getCurrentVisiblePage();
+    }
+
+    return super._getVisiblePages();
   }
 
   _updateHelper(visiblePages) {
     if (this.isInPresentationMode) {
       return;
     }
 
     let currentId = this._currentPageNumber;
@@ -8189,20 +8192,16 @@ class PDFViewer extends _base_viewer.Bas
 
     if (!stillFullyVisible) {
       currentId = visiblePages[0].id;
     }
 
     this._setCurrentPageNumber(currentId);
   }
 
-  get _isScrollModeHorizontal() {
-    return this.isInPresentationMode ? false : this._scrollMode === _base_viewer.ScrollMode.HORIZONTAL;
-  }
-
 }
 
 exports.PDFViewer = PDFViewer;
 
 /***/ }),
 /* 25 */
 /***/ (function(module, exports, __webpack_require__) {
 
@@ -8672,17 +8671,17 @@ class BaseViewer {
     this.update();
   }
 
   _scrollIntoView({
     pageDiv,
     pageSpot = null,
     pageNumber = null
   }) {
-    throw new Error('Not implemented: _scrollIntoView');
+    (0, _ui_utils.scrollIntoView)(pageDiv, pageSpot);
   }
 
   _setScaleUpdatePages(newScale, newValue, noScroll = false, preset = false) {
     this._currentScaleValue = newValue.toString();
 
     if (isSameScale(this._currentScale, newScale)) {
       if (preset) {
         this.eventBus.dispatch('scalechanging', {
@@ -8909,22 +8908,16 @@ class BaseViewer {
       pageSpot: {
         left,
         top
       },
       pageNumber
     });
   }
 
-  _resizeBuffer(numVisiblePages, visiblePages) {
-    let suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1);
-
-    this._buffer.resize(suggestedCacheSize, visiblePages);
-  }
-
   _updateLocation(firstPage) {
     let currentScale = this._currentScale;
     let currentScaleValue = this._currentScaleValue;
     let normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue;
     let pageNumber = firstPage.id;
     let pdfOpenParams = '#page=' + pageNumber;
     pdfOpenParams += '&zoom=' + normalizedScaleValue;
     let currentPageView = this._pages[pageNumber - 1];
@@ -8952,17 +8945,19 @@ class BaseViewer {
 
     const visiblePages = visible.views,
           numVisiblePages = visiblePages.length;
 
     if (numVisiblePages === 0) {
       return;
     }
 
-    this._resizeBuffer(numVisiblePages, visiblePages);
+    const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1);
+
+    this._buffer.resize(newCacheSize, visiblePages);
 
     this.renderingQueue.renderHighestPriority(visible);
 
     this._updateHelper(visiblePages);
 
     this._updateLocation(visible.first);
 
     this.eventBus.dispatch('updateviewarea', {
@@ -8975,17 +8970,17 @@ class BaseViewer {
     return this.container.contains(element);
   }
 
   focus() {
     this.container.focus();
   }
 
   get _isScrollModeHorizontal() {
-    throw new Error('Not implemented: _isScrollModeHorizontal');
+    return this.isInPresentationMode ? false : this._scrollMode === ScrollMode.HORIZONTAL;
   }
 
   get isInPresentationMode() {
     return this.presentationModeState === _ui_utils.PresentationModeState.FULLSCREEN;
   }
 
   get isChangingPresentationMode() {
     return this.presentationModeState === _ui_utils.PresentationModeState.CHANGING;
@@ -9017,17 +9012,17 @@ class BaseViewer {
     return {
       first: view,
       last: view,
       views: [view]
     };
   }
 
   _getVisiblePages() {
-    throw new Error('Not implemented: _getVisiblePages');
+    return (0, _ui_utils.getVisibleElements)(this.container, this._pages, true, this._isScrollModeHorizontal);
   }
 
   isPageVisible(pageNumber) {
     if (!this.pdfDocument) {
       return false;
     }
 
     if (this.pageNumber < 1 || pageNumber > this.pagesCount) {
@@ -9758,24 +9753,24 @@ class PDFPageView {
 
           return;
         }
 
         cont();
       };
     }
 
-    let finishPaintTask = error => {
+    const finishPaintTask = async error => {
       if (paintTask === this.paintTask) {
         this.paintTask = null;
       }
 
       if (error instanceof _pdfjsLib.RenderingCancelledException) {
         this.error = null;
-        return Promise.resolve(undefined);
+        return;
       }
 
       this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED;
 
       if (this.loadingIconDiv) {
         div.removeChild(this.loadingIconDiv);
         delete this.loadingIconDiv;
       }
@@ -9791,20 +9786,18 @@ class PDFPageView {
 
       this.eventBus.dispatch('pagerendered', {
         source: this,
         pageNumber: this.id,
         cssTransform: false
       });
 
       if (error) {
-        return Promise.reject(error);
-      }
-
-      return Promise.resolve(undefined);
+        throw error;
+      }
     };
 
     let paintTask = this.renderer === _ui_utils.RendererType.SVG ? this.paintOnSvg(canvasWrapper) : this.paintOnCanvas(canvasWrapper);
     paintTask.onRenderContinue = renderContinueCallback;
     this.paintTask = paintTask;
     let resultPromise = paintTask.promise.then(function () {
       return finishPaintTask(null).then(function () {
         if (textLayer) {
@@ -10700,18 +10693,16 @@ exports.SecondaryToolbar = SecondaryTool
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.PDFSinglePageViewer = void 0;
 
 var _base_viewer = __webpack_require__(25);
 
-var _ui_utils = __webpack_require__(2);
-
 var _pdfjsLib = __webpack_require__(3);
 
 class PDFSinglePageViewer extends _base_viewer.BaseViewer {
   constructor(options) {
     super(options);
     this.eventBus.on('pagesinit', evt => {
       this._ensurePageViewVisible();
     });
@@ -10721,16 +10712,17 @@ class PDFSinglePageViewer extends _base_
     return (0, _pdfjsLib.shadow)(this, '_setDocumentViewerElement', this._shadowViewer);
   }
 
   _resetView() {
     super._resetView();
 
     this._previousPageNumber = 1;
     this._shadowViewer = document.createDocumentFragment();
+    this._updateScrollDown = null;
   }
 
   _ensurePageViewVisible() {
     let pageView = this._pages[this._currentPageNumber - 1];
     let previousPageView = this._pages[this._previousPageNumber - 1];
     let viewerNodes = this.viewer.childNodes;
 
     switch (viewerNodes.length) {
@@ -10772,37 +10764,32 @@ class PDFSinglePageViewer extends _base_
     pageDiv,
     pageSpot = null,
     pageNumber = null
   }) {
     if (pageNumber) {
       this._setCurrentPageNumber(pageNumber);
     }
 
-    let scrolledDown = this._currentPageNumber >= this._previousPageNumber;
-    let previousLocation = this._location;
+    const scrolledDown = this._currentPageNumber >= this._previousPageNumber;
 
     this._ensurePageViewVisible();
 
-    (0, _ui_utils.scrollIntoView)(pageDiv, pageSpot);
+    this.update();
+
+    super._scrollIntoView({
+      pageDiv,
+      pageSpot,
+      pageNumber
+    });
 
     this._updateScrollDown = () => {
       this.scroll.down = scrolledDown;
-      delete this._updateScrollDown;
+      this._updateScrollDown = null;
     };
-
-    setTimeout(() => {
-      if (this._location === previousLocation) {
-        if (this._updateScrollDown) {
-          this._updateScrollDown();
-        }
-
-        this.update();
-      }
-    }, 0);
   }
 
   _getVisiblePages() {
     return this._getCurrentVisiblePage();
   }
 
   _updateHelper(visiblePages) {}
 
--- a/browser/extensions/pdfjs/moz.yaml
+++ b/browser/extensions/pdfjs/moz.yaml
@@ -15,15 +15,15 @@ origin:
   description: Portable Document Format (PDF) viewer that is built with HTML5
 
   # Full URL for the package's homepage/etc
   # Usually different from repository url
   url: https://github.com/mozilla/pdf.js
 
   # Human-readable identifier for this version/release
   # Generally "version NNN", "tag SSS", "bookmark SSS"
-  release: version 2.1.215
+  release: version 2.1.228
 
   # The package's license, where possible using the mnemonic from
   # https://spdx.org/licenses/
   # Multiple licenses can be specified (as a YAML list)
   # A "LICENSE" file must exist containing the full license text
   license: Apache-2.0
--- a/devtools/client/inspector/rules/components/Declaration.js
+++ b/devtools/client/inspector/rules/components/Declaration.js
@@ -104,16 +104,30 @@ class Declaration extends PureComponent 
               )
             )
           );
         })
       )
     );
   }
 
+  renderOverriddenFilter() {
+    if (this.props.declaration.isDeclarationValid) {
+      return null;
+    }
+
+    return (
+      dom.div({
+        className: "ruleview-warning",
+        title: this.props.declaration.isNameValid ?
+               getStr("rule.warningName.title") : getStr("rule.warning.title"),
+      })
+    );
+  }
+
   renderShorthandOverriddenList() {
     if (this.state.isComputedListExpanded || this.props.declaration.isOverridden) {
       return null;
     }
 
     const overriddenComputedProperties = this.props.declaration.computedProperties
       .filter(prop => prop.isOverridden);
 
@@ -140,23 +154,35 @@ class Declaration extends PureComponent 
               )
             )
           );
         })
       )
     );
   }
 
+  renderWarning() {
+    if (!this.props.declaration.isDeclarationValid ||
+        !this.props.declaration.isOverridden) {
+      return null;
+    }
+
+    return (
+      dom.div({
+        className: "ruleview-overridden-rule-filter",
+        title: getStr("rule.filterProperty.title"),
+      })
+    );
+  }
+
   render() {
     const {
       computedProperties,
-      isDeclarationValid,
       isEnabled,
       isKnownProperty,
-      isNameValid,
       isOverridden,
       name,
       value,
     } = this.props.declaration;
 
     return (
       dom.li(
         {
@@ -194,27 +220,18 @@ class Declaration extends PureComponent 
                 className: "ruleview-propertyvalue theme-fg-color1",
                 ref: this.valueSpanRef,
                 tabIndex: 0,
               },
               value
             ),
             ";"
           ),
-          dom.div({
-            className: "ruleview-warning" +
-                       (isDeclarationValid ? " hidden" : ""),
-            title: isNameValid ?
-                   getStr("rule.warningName.title") : getStr("rule.warning.title"),
-          }),
-          dom.div({
-            className: "ruleview-overridden-rule-filter" +
-                       (!isDeclarationValid || !isOverridden ? " hidden" : ""),
-            title: getStr("rule.filterProperty.title"),
-          })
+          this.renderWarning(),
+          this.renderOverriddenFilter()
         ),
         this.renderComputedPropertyList(),
         this.renderShorthandOverriddenList()
       )
     );
   }
 }
 
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -9,17 +9,16 @@
 const promise = require("promise");
 const Services = require("Services");
 const flags = require("devtools/shared/flags");
 const {l10n} = require("devtools/shared/inspector/css-logic");
 const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
 const OutputParser = require("devtools/client/shared/output-parser");
 const {PrefObserver} = require("devtools/client/shared/prefs");
 const ElementStyle = require("devtools/client/inspector/rules/models/element-style");
-const Rule = require("devtools/client/inspector/rules/models/rule");
 const RuleEditor = require("devtools/client/inspector/rules/views/rule-editor");
 const {
   VIEW_NODE_SELECTOR_TYPE,
   VIEW_NODE_PROPERTY_TYPE,
   VIEW_NODE_VALUE_TYPE,
   VIEW_NODE_IMAGE_URL_TYPE,
   VIEW_NODE_LOCATION_TYPE,
   VIEW_NODE_SHAPE_POINT_TYPE,
@@ -514,64 +513,23 @@ CssRuleView.prototype = {
 
       clipboardHelper.copyString(text);
     } catch (e) {
       console.error(e);
     }
   },
 
   /**
-   * A helper for _onAddRule that handles the case where the actor
-   * does not support as-authored styles.
-   */
-  _onAddNewRuleNonAuthored: function() {
-    const elementStyle = this._elementStyle;
-    const element = elementStyle.element;
-    const rules = elementStyle.rules;
-    const pseudoClasses = element.pseudoClassLocks;
-
-    this.pageStyle.addNewRule(element, pseudoClasses).then(options => {
-      const newRule = new Rule(elementStyle, options);
-      rules.push(newRule);
-      const editor = new RuleEditor(this, newRule);
-      newRule.editor = editor;
-
-      // Insert the new rule editor after the inline element rule
-      if (rules.length <= 1) {
-        this.element.appendChild(editor.element);
-      } else {
-        for (const rule of rules) {
-          if (rule.domRule.type === ELEMENT_STYLE) {
-            const referenceElement = rule.editor.element.nextSibling;
-            this.element.insertBefore(editor.element, referenceElement);
-            break;
-          }
-        }
-      }
-
-      // Focus and make the new rule's selector editable
-      editor.selectorText.click();
-      elementStyle._changed();
-    });
-  },
-
-  /**
    * Add a new rule to the current element.
    */
   _onAddRule: function() {
     const elementStyle = this._elementStyle;
     const element = elementStyle.element;
     const pseudoClasses = element.pseudoClassLocks;
 
-    if (!this.pageStyle.supportsAuthoredStyles) {
-      // We're talking to an old server.
-      this._onAddNewRuleNonAuthored();
-      return;
-    }
-
     // Adding a new rule with authored styles will cause the actor to
     // emit an event, which will in turn cause the rule view to be
     // updated.  So, we wait for this update and for the rule creation
     // request to complete, and then focus the new rule's selector.
     const eventPromise = this.once("ruleview-refreshed");
     const newRulePromise = this.pageStyle.addNewRule(element, pseudoClasses);
     promise.all([eventPromise, newRulePromise]).then((values) => {
       const options = values[1];
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -167,19 +167,17 @@
 .ruleview-propertyvaluecontainer a {
   color: var(--theme-highlight-purple);
   cursor: pointer;
 }
 
 .ruleview-computedlist,
 .ruleview-expandable-container[hidden],
 .ruleview-overridden-items[hidden],
-.ruleview-overridden-rule-filter.hidden,
 .ruleview-overridden-rule-filter[hidden],
-.ruleview-warning.hidden,
 .ruleview-warning[hidden],
 .ruleview-overridden .ruleview-grid {
   display: none;
 }
 
 .ruleview-computedlist[user-open],
 .ruleview-computedlist[filter-open],
 .ruleview-overridden-items {
--- a/devtools/server/actors/styles.js
+++ b/devtools/server/actors/styles.js
@@ -126,18 +126,16 @@ var PageStyleActor = protocol.ActorClass
     return {
       actor: this.actorID,
       traits: {
         // Whether the actor has had bug 1103993 fixed, which means that the
         // getApplied method calls cssLogic.highlight(node) to recreate the
         // style cache. Clients requesting getApplied from actors that have not
         // been fixed must make sure cssLogic.highlight(node) was called before.
         getAppliedCreatesStyleCache: true,
-        // Whether addNewRule accepts the editAuthored argument.
-        authoredStyles: true,
         // Whether the page supports values of font-stretch from CSS Fonts Level 4.
         fontStretchLevel4: CSS.supports("font-stretch: 100%"),
         // Whether the page supports values of font-style from CSS Fonts Level 4.
         fontStyleLevel4: CSS.supports("font-style: oblique 20deg"),
         // Whether getAllUsedFontFaces/getUsedFontFaces accepts the includeVariations
         // argument.
         fontVariations: FONT_VARIATIONS_ENABLED,
         // Whether the page supports values of font-weight from CSS Fonts Level 4.
@@ -931,23 +929,19 @@ var PageStyleActor = protocol.ActorClass
       { matchedSelectors: true });
   },
 
   /**
    * Adds a new rule, and returns the new StyleRuleActor.
    * @param {NodeActor} node
    * @param {String} pseudoClasses The list of pseudo classes to append to the
    *        new selector.
-   * @param {Boolean} editAuthored
-   *        True if the selector should be updated by editing the
-   *        authored text; false if the selector should be updated via
-   *        CSSOM.
    * @returns {StyleRuleActor} the new rule
    */
-  async addNewRule(node, pseudoClasses, editAuthored = false) {
+  async addNewRule(node, pseudoClasses) {
     const style = this.getStyleElement(node.rawNode.ownerDocument);
     const sheet = style.sheet;
     const cssRules = sheet.cssRules;
     const rawNode = node.rawNode;
     const classes = [...rawNode.classList];
 
     let selector;
     if (rawNode.id) {
@@ -961,22 +955,20 @@ var PageStyleActor = protocol.ActorClass
     if (pseudoClasses && pseudoClasses.length > 0) {
       selector += pseudoClasses.join("");
     }
 
     const index = sheet.insertRule(selector + " {}", cssRules.length);
 
     // If inserting the rule succeeded, go ahead and edit the source
     // text if requested.
-    if (editAuthored) {
-      const sheetActor = this._sheetRef(sheet);
-      let {str: authoredText} = await sheetActor.getText();
-      authoredText += "\n" + selector + " {\n" + "}";
-      await sheetActor.update(authoredText, false);
-    }
+    const sheetActor = this._sheetRef(sheet);
+    let {str: authoredText} = await sheetActor.getText();
+    authoredText += "\n" + selector + " {\n" + "}";
+    await sheetActor.update(authoredText, false);
 
     return this.getNewAppliedProps(node, sheet.cssRules.item(index));
   },
 });
 exports.PageStyleActor = PageStyleActor;
 
 /**
  * An actor that represents a CSS style object on the protocol.
--- a/devtools/shared/fronts/styles.js
+++ b/devtools/shared/fronts/styles.js
@@ -32,20 +32,16 @@ class PageStyleFront extends FrontClassW
     }
     this._form = form;
   }
 
   get walker() {
     return this.inspector.walker;
   }
 
-  get supportsAuthoredStyles() {
-    return this._form.traits && this._form.traits.authoredStyles;
-  }
-
   get supportsFontStretchLevel4() {
     return this._form.traits && this._form.traits.fontStretchLevel4;
   }
 
   get supportsFontStyleLevel4() {
     return this._form.traits && this._form.traits.fontStyleLevel4;
   }
 
@@ -71,23 +67,17 @@ class PageStyleFront extends FrontClassW
     if (!this._form.traits || !this._form.traits.getAppliedCreatesStyleCache) {
       await this.getLayout(node);
     }
     const ret = await super.getApplied(node, options);
     return ret.entries;
   }
 
   addNewRule(node, pseudoClasses) {
-    let addPromise;
-    if (this.supportsAuthoredStyles) {
-      addPromise = super.addNewRule(node, pseudoClasses, true);
-    } else {
-      addPromise = super.addNewRule(node, pseudoClasses);
-    }
-    return addPromise.then(ret => {
+    return super.addNewRule(node, pseudoClasses).then(ret => {
       return ret.entries[0];
     });
   }
 }
 
 exports.PageStyleFront = PageStyleFront;
 registerFront(PageStyleFront);
 
--- a/devtools/shared/specs/styles.js
+++ b/devtools/shared/specs/styles.js
@@ -170,17 +170,16 @@ const pageStyleSpec = generateActorSpec(
         autoMargins: Option(1, "boolean"),
       },
       response: RetVal("json"),
     },
     addNewRule: {
       request: {
         node: Arg(0, "domnode"),
         pseudoClasses: Arg(1, "nullable:array:string"),
-        editAuthored: Arg(2, "boolean"),
       },
       response: RetVal("appliedStylesReturn"),
     },
   },
 });
 
 exports.pageStyleSpec = pageStyleSpec;
 
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -314,16 +314,18 @@ using mozilla::TimeStamp;
   }                                                     \
   return GetCurrentInnerWindowInternal()->method args;  \
   PR_END_MACRO
 
 static LazyLogModule gDOMLeakPRLogOuter("DOMLeakOuter");
 
 static int32_t gOpenPopupSpamCount = 0;
 
+static bool gSyncContentBlockingNotifications = false;
+
 nsGlobalWindowOuter::OuterWindowByIdTable*
     nsGlobalWindowOuter::sOuterWindowsById = nullptr;
 
 /* static */
 nsPIDOMWindowOuter* nsPIDOMWindowOuter::GetFromCurrentInner(
     nsPIDOMWindowInner* aInner) {
   if (!aInner) {
     return nullptr;
@@ -5356,110 +5358,141 @@ void nsGlobalWindowOuter::NotifyContentB
 
   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
   if (!docShell) {
     return;
   }
   nsCOMPtr<Document> doc = docShell->GetDocument();
   NS_ENSURE_TRUE_VOID(doc);
 
-  // This event might come after the user has navigated to another page.
-  // To prevent showing the TrackingProtection UI on the wrong page, we need to
-  // check that the loading URI for the channel is the same as the URI currently
-  // loaded in the document.
-  if (!SameLoadingURI(doc, aChannel) &&
-      aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
-    return;
-  }
-
-  // Notify nsIWebProgressListeners of this content blocking event.
-  // Can be used to change the UI state.
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
-  NS_ENSURE_SUCCESS_VOID(rv);
-  uint32_t event = 0;
-  nsCOMPtr<nsISecureBrowserUI> securityUI;
-  docShell->GetSecurityUI(getter_AddRefs(securityUI));
-  if (!securityUI) {
+  nsCOMPtr<nsIURI> uri(aURIHint);
+  nsCOMPtr<nsIChannel> channel(aChannel);
+
+  static bool prefInitialized = false;
+  if (!prefInitialized) {
+    Preferences::AddBoolVarCache(
+        &gSyncContentBlockingNotifications,
+        "dom.testing.sync-content-blocking-notifications", false);
+    prefInitialized = true;
+  }
+
+  nsCOMPtr<nsIRunnable> func = NS_NewRunnableFunction(
+      "NotifyContentBlockingEventDelayed",
+      [doc, docShell, uri, channel, aEvent, aBlocked]() {
+        // This event might come after the user has navigated to another
+        // page. To prevent showing the TrackingProtection UI on the wrong
+        // page, we need to check that the loading URI for the channel is
+        // the same as the URI currently loaded in the document.
+        if (!SameLoadingURI(doc, channel) &&
+            aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
+          return;
+        }
+
+        // Notify nsIWebProgressListeners of this content blocking event.
+        // Can be used to change the UI state.
+        nsresult rv = NS_OK;
+        nsCOMPtr<nsISecurityEventSink> eventSink =
+            do_QueryInterface(docShell, &rv);
+        NS_ENSURE_SUCCESS_VOID(rv);
+        uint32_t event = 0;
+        nsCOMPtr<nsISecureBrowserUI> securityUI;
+        docShell->GetSecurityUI(getter_AddRefs(securityUI));
+        if (!securityUI) {
+          return;
+        }
+        securityUI->GetContentBlockingEvent(&event);
+        nsAutoCString origin;
+        nsContentUtils::GetASCIIOrigin(uri, origin);
+
+        bool blockedValue = aBlocked;
+        bool unblocked = false;
+        if (aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
+          doc->SetHasTrackingContentBlocked(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasTrackingContentBlocked();
+          }
+        } else if (aEvent ==
+                   nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
+          doc->SetHasTrackingContentLoaded(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasTrackingContentLoaded();
+          }
+        } else if (aEvent == nsIWebProgressListener::
+                                 STATE_COOKIES_BLOCKED_BY_PERMISSION) {
+          doc->SetHasCookiesBlockedByPermission(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasCookiesBlockedByPermission();
+          }
+        } else if (aEvent ==
+                   nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER) {
+          doc->SetHasTrackingCookiesBlocked(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasTrackingCookiesBlocked();
+          }
+        } else if (aEvent ==
+                   nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL) {
+          doc->SetHasAllCookiesBlocked(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasAllCookiesBlocked();
+          }
+        } else if (aEvent ==
+                   nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) {
+          doc->SetHasForeignCookiesBlocked(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasForeignCookiesBlocked();
+          }
+        } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_LOADED) {
+          MOZ_ASSERT(!aBlocked,
+                     "We don't expected to see blocked STATE_COOKIES_LOADED");
+          // Note that the logic in this branch is the logical negation of
+          // the logic in other branches, since the Document API we have is
+          // phrased in "loaded" terms as opposed to "blocked" terms.
+          blockedValue = !aBlocked;
+          doc->SetHasCookiesLoaded(blockedValue, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasCookiesLoaded();
+          }
+        } else {
+          // Ignore nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
+        }
+        const uint32_t oldEvent = event;
+        if (blockedValue) {
+          event |= aEvent;
+        } else if (unblocked) {
+          event &= ~aEvent;
+        }
+
+        if (event == oldEvent
+#ifdef ANDROID
+            // GeckoView always needs to notify about blocked trackers,
+            // since the GeckoView API always needs to report the URI and
+            // type of any blocked tracker. We use a platform-dependent code
+            // path here because reporting this notification on desktop
+            // platforms isn't necessary and doing so can have a big
+            // performance cost.
+            && aEvent != nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT
+#endif
+        ) {
+          // Avoid dispatching repeated notifications when nothing has
+          // changed
+          return;
+        }
+
+        eventSink->OnContentBlockingEvent(channel, event);
+      });
+  nsresult rv;
+  if (gSyncContentBlockingNotifications) {
+    rv = func->Run();
+  } else {
+    rv = NS_DispatchToCurrentThreadQueue(func.forget(), 100,
+                                         EventQueuePriority::Idle);
+  }
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
-  securityUI->GetContentBlockingEvent(&event);
-  nsAutoCString origin;
-  nsContentUtils::GetASCIIOrigin(aURIHint, origin);
-
-  bool blockedValue = aBlocked;
-  bool unblocked = false;
-  if (aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
-    doc->SetHasTrackingContentBlocked(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasTrackingContentBlocked();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
-    doc->SetHasTrackingContentLoaded(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasTrackingContentLoaded();
-    }
-  } else if (aEvent ==
-             nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION) {
-    doc->SetHasCookiesBlockedByPermission(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasCookiesBlockedByPermission();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER) {
-    doc->SetHasTrackingCookiesBlocked(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasTrackingCookiesBlocked();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL) {
-    doc->SetHasAllCookiesBlocked(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasAllCookiesBlocked();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) {
-    doc->SetHasForeignCookiesBlocked(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasForeignCookiesBlocked();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_LOADED) {
-    MOZ_ASSERT(!aBlocked,
-               "We don't expected to see blocked STATE_COOKIES_LOADED");
-    // Note that the logic in this branch is the logical negation of the logic
-    // in other branches, since the Document API we have is phrased in
-    // "loaded" terms as opposed to "blocked" terms.
-    blockedValue = !aBlocked;
-    doc->SetHasCookiesLoaded(blockedValue, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasCookiesLoaded();
-    }
-  } else {
-    // Ignore nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
-  }
-  const uint32_t oldEvent = event;
-  if (blockedValue) {
-    event |= aEvent;
-  } else if (unblocked) {
-    event &= ~aEvent;
-  }
-
-  if (event == oldEvent
-#ifdef ANDROID
-      // GeckoView always needs to notify about blocked trackers, since the
-      // GeckoView API always needs to report the URI and type of any blocked
-      // tracker.
-      // We use a platform-dependent code path here because reporting this
-      // notification on desktop platforms isn't necessary and doing so can have
-      // a big performance cost.
-      && aEvent != nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT
-#endif
-  ) {
-    // Avoid dispatching repeated notifications when nothing has changed
-    return;
-  }
-
-  eventSink->OnContentBlockingEvent(aChannel, event);
 }
 
 // static
 bool nsGlobalWindowOuter::SameLoadingURI(Document* aDoc, nsIChannel* aChannel) {
   nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
   nsCOMPtr<nsILoadInfo> channelLoadInfo = aChannel->GetLoadInfo();
   if (!channelLoadInfo || !docURI) {
     return false;
--- a/dom/cache/ReadStream.cpp
+++ b/dom/cache/ReadStream.cpp
@@ -218,20 +218,22 @@ void ReadStream::Inner::Serialize(
   aReadStreamOut->id() = mId;
   mControl->SerializeControl(aReadStreamOut);
 
   {
     MutexAutoLock lock(mMutex);
     mControl->SerializeStream(aReadStreamOut, mStream, aStreamCleanupList);
   }
 
-  MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut->stream().type() ==
-                            OptionalIPCStream::Tvoid_t ||
-                        aReadStreamOut->stream().get_IPCStream().type() ==
-                            IPCStream::TInputStreamParamsWithFds);
+  MOZ_DIAGNOSTIC_ASSERT(
+      aReadStreamOut->stream().type() == OptionalIPCStream::Tvoid_t ||
+      (aReadStreamOut->stream().get_IPCStream().stream().type() !=
+           mozilla::ipc::InputStreamParams::TIPCRemoteStreamParams &&
+       aReadStreamOut->stream().get_IPCStream().stream().type() !=
+           mozilla::ipc::InputStreamParams::T__None));
 
   // We're passing ownership across the IPC barrier with the control, so
   // do not signal that the stream is closed here.
   Forget();
 }
 
 void ReadStream::Inner::CloseStream() {
   MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
@@ -514,20 +516,22 @@ already_AddRefed<ReadStream> ReadStream:
     const CacheReadStream& aReadStream) {
   // The parameter may or may not be for a Cache created stream.  The way we
   // tell is by looking at the stream control actor.  If the actor exists,
   // then we know the Cache created it.
   if (!aReadStream.controlChild() && !aReadStream.controlParent()) {
     return nullptr;
   }
 
-  MOZ_DIAGNOSTIC_ASSERT(aReadStream.stream().type() ==
-                            OptionalIPCStream::Tvoid_t ||
-                        aReadStream.stream().get_IPCStream().type() ==
-                            IPCStream::TInputStreamParamsWithFds);
+  MOZ_DIAGNOSTIC_ASSERT(
+      aReadStream.stream().type() == OptionalIPCStream::Tvoid_t ||
+      (aReadStream.stream().get_IPCStream().stream().type() !=
+           mozilla::ipc::InputStreamParams::TIPCRemoteStreamParams &&
+       aReadStream.stream().get_IPCStream().stream().type() !=
+           mozilla::ipc::InputStreamParams::T__None));
 
   // Control is guaranteed to survive this method as ActorDestroy() cannot
   // run on this thread until we complete.
   StreamControl* control;
   if (aReadStream.controlChild()) {
     auto actor =
         static_cast<CacheStreamControlChild*>(aReadStream.controlChild());
     control = actor;
--- a/dom/file/TemporaryFileBlobImpl.cpp
+++ b/dom/file/TemporaryFileBlobImpl.cpp
@@ -46,17 +46,36 @@ class TemporaryFileInputStream final : p
       return rv;
     }
 
     stream.forget(aInputStream);
     return NS_OK;
   }
 
   void Serialize(InputStreamParams& aParams,
-                 FileDescriptorArray& aFileDescriptors) override {
+                 FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+                 nsIContentChild* aManager) override {
+    MOZ_CRASH("This inputStream cannot be serialized.");
+  }
+
+  void Serialize(InputStreamParams& aParams,
+                 FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+                 PBackgroundChild* aManager) override {
+    MOZ_CRASH("This inputStream cannot be serialized.");
+  }
+
+  void Serialize(InputStreamParams& aParams,
+                 FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+                 nsIContentParent* aManager) override {
+    MOZ_CRASH("This inputStream cannot be serialized.");
+  }
+
+  void Serialize(InputStreamParams& aParams,
+                 FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+                 PBackgroundParent* aManager) override {
     MOZ_CRASH("This inputStream cannot be serialized.");
   }
 
   bool Deserialize(const InputStreamParams& aParams,
                    const FileDescriptorArray& aFileDescriptors) override {
     MOZ_CRASH("This inputStream cannot be deserialized.");
     return false;
   }
--- a/dom/file/ipc/IPCBlobInputStream.cpp
+++ b/dom/file/ipc/IPCBlobInputStream.cpp
@@ -559,17 +559,45 @@ IPCBlobInputStream::OnInputStreamReady(n
   MOZ_ASSERT(callback);
   InputStreamCallbackRunnable::Execute(callback, callbackEventTarget, this);
   return NS_OK;
 }
 
 // nsIIPCSerializableInputStream
 
 void IPCBlobInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
-                                   FileDescriptorArray& aFileDescriptors) {
+                                   FileDescriptorArray& aFileDescriptors,
+                                   bool aDelayedStart,
+                                   nsIContentChild* aManager) {
+  SerializeInternal(aParams);
+}
+
+void IPCBlobInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
+                                   FileDescriptorArray& aFileDescriptors,
+                                   bool aDelayedStart,
+                                   mozilla::ipc::PBackgroundChild* aManager) {
+  SerializeInternal(aParams);
+}
+
+void IPCBlobInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
+                                   FileDescriptorArray& aFileDescriptors,
+                                   bool aDelayedStart,
+                                   nsIContentParent* aManager) {
+  SerializeInternal(aParams);
+}
+
+void IPCBlobInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
+                                   FileDescriptorArray& aFileDescriptors,
+                                   bool aDelayedStart,
+                                   mozilla::ipc::PBackgroundParent* aManager) {
+  SerializeInternal(aParams);
+}
+
+void IPCBlobInputStream::SerializeInternal(
+    mozilla::ipc::InputStreamParams& aParams) {
   MutexAutoLock lock(mMutex);
 
   mozilla::ipc::IPCBlobInputStreamParams params;
   params.id() = mActor->ID();
   params.start() = mStart;
   params.length() = mLength;
 
   aParams = params;
@@ -577,20 +605,16 @@ void IPCBlobInputStream::Serialize(mozil
 
 bool IPCBlobInputStream::Deserialize(
     const mozilla::ipc::InputStreamParams& aParams,
     const FileDescriptorArray& aFileDescriptors) {
   MOZ_CRASH("This should never be called.");
   return false;
 }
 
-mozilla::Maybe<uint64_t> IPCBlobInputStream::ExpectedSerializedLength() {
-  return mozilla::Nothing();
-}
-
 // nsIAsyncFileMetadata
 
 NS_IMETHODIMP
 IPCBlobInputStream::AsyncFileMetadataWait(nsIFileMetadataCallback* aCallback,
                                           nsIEventTarget* aEventTarget) {
   MOZ_ASSERT(!!aCallback == !!aEventTarget);
 
   // If we have the callback, we must have the event target.
--- a/dom/file/ipc/IPCBlobInputStream.h
+++ b/dom/file/ipc/IPCBlobInputStream.h
@@ -58,16 +58,18 @@ class IPCBlobInputStream final : public 
   NS_DECL_NSIASYNCINPUTSTREAMLENGTH
 
   explicit IPCBlobInputStream(IPCBlobInputStreamChild* aActor);
 
   void StreamReady(already_AddRefed<nsIInputStream> aInputStream);
 
   void LengthReady(int64_t aLength);
 
+  void SerializeInternal(mozilla::ipc::InputStreamParams& aParams);
+
   // nsIIPCBlobInputStream
   nsIInputStream* GetInternalStream() const override {
     if (mRemoteStream) {
       return mRemoteStream;
     }
 
     if (mAsyncRemoteStream) {
       return mAsyncRemoteStream;
--- a/dom/file/ipc/tests/mochitest.ini
+++ b/dom/file/ipc/tests/mochitest.ini
@@ -1,8 +1,10 @@
 [DEFAULT]
 support-files = script_file.js
 
 [test_ipcBlob_fileReaderSync.html]
 [test_ipcBlob_workers.html]
 [test_ipcBlob_createImageBitmap.html]
 support-files = green.jpg
 [test_ipcBlob_emptyMultiplex.html]
+[test_ipcBlob_mixedMultiplex.html]
+support-files = ok.sjs
new file mode 100644
--- /dev/null
+++ b/dom/file/ipc/tests/ok.sjs
@@ -0,0 +1,10 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+                             "nsIBinaryInputStream",
+                             "setInputStream");
+
+function handleRequest(request, response)
+{
+  response.setHeader("Content-Type", "text/html", false);
+  response.write(request.getHeader("Content-Length"));
+}
new file mode 100644
--- /dev/null
+++ b/dom/file/ipc/tests/test_ipcBlob_mixedMultiplex.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test an empty IPCBlob together with other parts</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script type="text/javascript">
+
+let url = SimpleTest.getTestFileURL("script_file.js");
+let data = new Array(1024*1024).join('A');
+
+let script = SpecialPowers.loadChromeScript(url);
+script.addMessageListener("file.opened", message => {
+  let blob = new Blob([data]);
+
+  let form = new FormData();
+  form.append("blob1", blob);
+  form.append("blob2", message.file);
+  form.append("blob3", blob);
+
+  fetch("ok.sjs", {
+    method: "POST",
+    body: form,
+  })
+  .then(r => r.text())
+  .then(r => {
+    ok(parseInt(r, 10) > (data.length * 2), "We have data");
+  })
+  . then(SimpleTest.finish);
+});
+
+script.sendAsyncMessage("file.open");
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/html/test/forms/mochitest.ini
+++ b/dom/html/test/forms/mochitest.ini
@@ -112,12 +112,13 @@ skip-if = android_version == '18' || os 
 [test_textarea_attributes_reflection.html]
 [test_validation.html]
 [test_valueAsDate_pref.html]
 [test_valueasdate_attribute.html]
 [test_valueasnumber_attribute.html]
 [test_validation_not_in_doc.html]
 [test_reportValidation_preventDefault.html]
 [test_bug1495363.html]
+skip-if = (webrender && os == "linux") # Bug 1520674
 support-files =
   file_bug1495363.html
   file_bug1495363.sjs
   !/dom/filesystem/tests/script_fileList.js
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -12270,22 +12270,17 @@ void Database::MapBlob(const IPCBlob& aI
 already_AddRefed<FileInfo> Database::GetBlob(const IPCBlob& aIPCBlob) {
   AssertIsOnBackgroundThread();
 
   const IPCBlobStream& stream = aIPCBlob.inputStream();
   MOZ_ASSERT(stream.type() == IPCBlobStream::TIPCStream);
 
   const IPCStream& ipcStream = stream.get_IPCStream();
 
-  if (ipcStream.type() != IPCStream::TInputStreamParamsWithFds) {
-    return nullptr;
-  }
-
-  const InputStreamParams& inputStreamParams =
-      ipcStream.get_InputStreamParamsWithFds().stream();
+  const InputStreamParams& inputStreamParams = ipcStream.stream();
   if (inputStreamParams.type() !=
       InputStreamParams::TIPCBlobInputStreamParams) {
     return nullptr;
   }
 
   const nsID& id = inputStreamParams.get_IPCBlobInputStreamParams().id();
 
   RefPtr<FileInfo> fileInfo;
--- a/dom/indexedDB/FileSnapshot.cpp
+++ b/dom/indexedDB/FileSnapshot.cpp
@@ -53,16 +53,21 @@ class StreamWrapper final : public nsIAs
     aFileHandle->AssertIsOnOwningThread();
 
     mFileHandle->OnNewRequest();
   }
 
  private:
   virtual ~StreamWrapper();
 
+  template <typename M>
+  void SerializeInternal(InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart, M* aManager);
+
   bool IsOnOwningThread() const {
     MOZ_ASSERT(mOwningThread);
 
     bool current;
     return NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(&current)) && current;
   }
 
   void AssertIsOnOwningThread() const { MOZ_ASSERT(IsOnOwningThread()); }
@@ -260,41 +265,57 @@ StreamWrapper::ReadSegments(nsWriteSegme
 }
 
 NS_IMETHODIMP
 StreamWrapper::IsNonBlocking(bool* _retval) {
   return mInputStream->IsNonBlocking(_retval);
 }
 
 void StreamWrapper::Serialize(InputStreamParams& aParams,
-                              FileDescriptorArray& aFileDescriptors) {
+                              FileDescriptorArray& aFileDescriptors,
+                              bool aDelayedStart, nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void StreamWrapper::Serialize(InputStreamParams& aParams,
+                              FileDescriptorArray& aFileDescriptors,
+                              bool aDelayedStart, PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void StreamWrapper::Serialize(InputStreamParams& aParams,
+                              FileDescriptorArray& aFileDescriptors,
+                              bool aDelayedStart, nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void StreamWrapper::Serialize(InputStreamParams& aParams,
+                              FileDescriptorArray& aFileDescriptors,
+                              bool aDelayedStart, PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+template <typename M>
+void StreamWrapper::SerializeInternal(InputStreamParams& aParams,
+                                      FileDescriptorArray& aFileDescriptors,
+                                      bool aDelayedStart, M* aManager) {
   nsCOMPtr<nsIIPCSerializableInputStream> stream =
       do_QueryInterface(mInputStream);
 
   if (stream) {
-    stream->Serialize(aParams, aFileDescriptors);
+    stream->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);
   }
 }
 
 bool StreamWrapper::Deserialize(const InputStreamParams& aParams,
                                 const FileDescriptorArray& aFileDescriptors) {
   MOZ_CRASH("This method should never be called");
   return false;
 }
 
-Maybe<uint64_t> StreamWrapper::ExpectedSerializedLength() {
-  nsCOMPtr<nsIIPCSerializableInputStream> stream =
-      do_QueryInterface(mInputStream);
-
-  if (stream) {
-    return stream->ExpectedSerializedLength();
-  }
-  return Nothing();
-}
-
 NS_IMETHODIMP
 StreamWrapper::CloseWithStatus(nsresult aStatus) {
   nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mInputStream);
   if (!stream) {
     return NS_ERROR_NO_INTERFACE;
   }
 
   nsresult rv = stream->CloseWithStatus(aStatus);
--- a/ipc/glue/IPCStream.ipdlh
+++ b/ipc/glue/IPCStream.ipdlh
@@ -7,51 +7,25 @@ include protocol PParentToChildStream;
 
 include BlobTypes;
 include InputStreamParams;
 include ProtocolTypes;
 
 namespace mozilla {
 namespace ipc {
 
-// Do not use this directly.  See IPCStream below.
-struct InputStreamParamsWithFds
+// Use IPCStream or OptionalIPCStream in your ipdl to represent serialized
+// nsIInputStreams.  Then use AutoIPCStream from IPCStreamUtils.h to perform
+// the serialization.
+struct IPCStream
 {
   InputStreamParams stream;
   OptionalFileDescriptorSet optionalFds;
 };
 
-union IPCRemoteStreamType
-{
-  PChildToParentStream;
-  PParentToChildStream;
-};
-
-struct IPCRemoteStream
-{
-  // If this is true, the stream will send data only when the first operation
-  // is done on the destination side. The benefit of this is that we do not
-  // send data if not needed. On the other hand, it could have a performance
-  // issue.
-  bool delayedStart;
-
-  IPCRemoteStreamType stream;
-
-  int64_t length;
-};
-
-// Use IPCStream or OptionalIPCStream in your ipdl to represent serialized
-// nsIInputStreams.  Then use AutoIPCStream from IPCStreamUtils.h to perform
-// the serialization.
-union IPCStream
-{
-  InputStreamParamsWithFds;
-  IPCRemoteStream;
-};
-
 union OptionalIPCStream
 {
   IPCStream;
   void_t;
 };
 
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/IPCStreamUtils.cpp
+++ b/ipc/glue/IPCStreamUtils.cpp
@@ -4,201 +4,141 @@
  * 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 "IPCStreamUtils.h"
 
 #include "nsIIPCSerializableInputStream.h"
 
 #include "mozilla/Assertions.h"
-#include "mozilla/InputStreamLengthHelper.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
-#include "mozilla/ipc/IPCStreamDestination.h"
-#include "mozilla/ipc/IPCStreamSource.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PBackgroundParent.h"
 #include "mozilla/Unused.h"
-#include "nsIAsyncInputStream.h"
-#include "nsIAsyncOutputStream.h"
-#include "nsIPipe.h"
 #include "nsNetCID.h"
-#include "nsStreamUtils.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 namespace ipc {
 
 namespace {
 
-void AssertValidValueToTake(const IPCStream& aVal) {
-  MOZ_ASSERT(aVal.type() == IPCStream::TIPCRemoteStream ||
-             aVal.type() == IPCStream::TInputStreamParamsWithFds);
-}
-
-void AssertValidValueToTake(const OptionalIPCStream& aVal) {
-  MOZ_ASSERT(aVal.type() == OptionalIPCStream::Tvoid_t ||
-             aVal.type() == OptionalIPCStream::TIPCStream);
-  if (aVal.type() == OptionalIPCStream::TIPCStream) {
-    AssertValidValueToTake(aVal.get_IPCStream());
-  }
-}
-
 // These serialization and cleanup functions could be externally exposed.  For
 // now, though, keep them private to encourage use of the safer RAII
 // AutoIPCStream class.
 
 template <typename M>
 bool SerializeInputStreamWithFdsChild(nsIIPCSerializableInputStream* aStream,
-                                      IPCStream& aValue, M* aManager) {
+                                      IPCStream& aValue, bool aDelayedStart,
+                                      M* aManager) {
   MOZ_RELEASE_ASSERT(aStream);
   MOZ_ASSERT(aManager);
 
-  aValue = InputStreamParamsWithFds();
-  InputStreamParamsWithFds& streamWithFds =
-      aValue.get_InputStreamParamsWithFds();
+  AutoTArray<FileDescriptor, 4> fds;
+  aStream->Serialize(aValue.stream(), fds, aDelayedStart, aManager);
 
-  AutoTArray<FileDescriptor, 4> fds;
-  aStream->Serialize(streamWithFds.stream(), fds);
-
-  if (streamWithFds.stream().type() == InputStreamParams::T__None) {
+  if (aValue.stream().type() == InputStreamParams::T__None) {
     MOZ_CRASH("Serialize failed!");
   }
 
   if (fds.IsEmpty()) {
-    streamWithFds.optionalFds() = void_t();
+    aValue.optionalFds() = void_t();
   } else {
     PFileDescriptorSetChild* fdSet =
         aManager->SendPFileDescriptorSetConstructor(fds[0]);
     for (uint32_t i = 1; i < fds.Length(); ++i) {
       Unused << fdSet->SendAddFileDescriptor(fds[i]);
     }
 
-    streamWithFds.optionalFds() = fdSet;
+    aValue.optionalFds() = fdSet;
   }
 
   return true;
 }
 
 template <typename M>
 bool SerializeInputStreamWithFdsParent(nsIIPCSerializableInputStream* aStream,
-                                       IPCStream& aValue, M* aManager) {
+                                       IPCStream& aValue, bool aDelayedStart,
+                                       M* aManager) {
   MOZ_RELEASE_ASSERT(aStream);
   MOZ_ASSERT(aManager);
 
-  aValue = InputStreamParamsWithFds();
-  InputStreamParamsWithFds& streamWithFds =
-      aValue.get_InputStreamParamsWithFds();
+  AutoTArray<FileDescriptor, 4> fds;
+  aStream->Serialize(aValue.stream(), fds, aDelayedStart, aManager);
 
-  AutoTArray<FileDescriptor, 4> fds;
-  aStream->Serialize(streamWithFds.stream(), fds);
-
-  if (streamWithFds.stream().type() == InputStreamParams::T__None) {
+  if (aValue.stream().type() == InputStreamParams::T__None) {
     MOZ_CRASH("Serialize failed!");
   }
 
-  streamWithFds.optionalFds() = void_t();
+  aValue.optionalFds() = void_t();
   if (!fds.IsEmpty()) {
     PFileDescriptorSetParent* fdSet =
         aManager->SendPFileDescriptorSetConstructor(fds[0]);
     for (uint32_t i = 1; i < fds.Length(); ++i) {
       if (NS_WARN_IF(!fdSet->SendAddFileDescriptor(fds[i]))) {
         Unused << PFileDescriptorSetParent::Send__delete__(fdSet);
         fdSet = nullptr;
         break;
       }
     }
 
     if (fdSet) {
-      streamWithFds.optionalFds() = fdSet;
+      aValue.optionalFds() = fdSet;
     }
   }
 
   return true;
 }
 
 template <typename M>
 bool SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue,
                           M* aManager, bool aDelayedStart) {
   MOZ_ASSERT(aStream);
   MOZ_ASSERT(aManager);
 
-  // Let's try to take the length using InputStreamLengthHelper. If the length
-  // cannot be taken synchronously, and its length is needed, the stream needs
-  // to be fully copied in memory on the deserialization side.
-  int64_t length;
-  if (!InputStreamLengthHelper::GetSyncLength(aStream, &length)) {
-    length = -1;
+  InputStreamParams params;
+  InputStreamHelper::SerializeInputStreamAsPipe(aStream, params, aDelayedStart,
+                                                aManager);
+
+  if (params.type() == InputStreamParams::T__None) {
+    return false;
   }
 
-  // As a fallback, attempt to stream the data across using a IPCStream
-  // actor. For blocking streams, create a nonblocking pipe instead,
-  nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
-  if (!asyncStream) {
-    const uint32_t kBufferSize = 32768;  // matches IPCStream buffer size.
-    nsCOMPtr<nsIAsyncOutputStream> sink;
-    nsresult rv = NS_NewPipe2(getter_AddRefs(asyncStream), getter_AddRefs(sink),
-                              true, false, kBufferSize, UINT32_MAX);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return false;
-    }
-
-    nsCOMPtr<nsIEventTarget> target =
-        do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
-
-    rv = NS_AsyncCopy(aStream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS,
-                      kBufferSize);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return false;
-    }
-  }
-
-  MOZ_ASSERT(asyncStream);
-
-  IPCRemoteStream remoteStream;
-  remoteStream.delayedStart() = aDelayedStart;
-  remoteStream.stream() = IPCStreamSource::Create(asyncStream, aManager);
-  remoteStream.length() = length;
-  aValue = remoteStream;
+  aValue.stream() = params;
+  aValue.optionalFds() = void_t();
 
   return true;
 }
 
 template <typename M>
 bool SerializeInputStreamChild(nsIInputStream* aStream, M* aManager,
                                IPCStream* aValue,
                                OptionalIPCStream* aOptionalValue,
                                bool aDelayedStart) {
   MOZ_ASSERT(aStream);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(aValue || aOptionalValue);
 
-  // If a stream is known to be larger than 1MB, prefer sending it in chunks.
-  const uint64_t kTooLargeStream = 1024 * 1024;
-
   nsCOMPtr<nsIIPCSerializableInputStream> serializable =
       do_QueryInterface(aStream);
 
-  // ExpectedSerializedLength() returns the length of the stream if serialized.
-  // This is useful to decide if we want to continue using the serialization
-  // directly, or if it's better to use IPCStream.
-  uint64_t expectedLength =
-      serializable ? serializable->ExpectedSerializedLength().valueOr(0) : 0;
-  if (serializable && expectedLength < kTooLargeStream) {
+  if (serializable) {
     if (aValue) {
-      return SerializeInputStreamWithFdsChild(serializable, *aValue, aManager);
+      return SerializeInputStreamWithFdsChild(serializable, *aValue,
+                                              aDelayedStart, aManager);
     }
 
     return SerializeInputStreamWithFdsChild(serializable, *aOptionalValue,
-                                            aManager);
+                                            aDelayedStart, aManager);
   }
 
   if (aValue) {
     return SerializeInputStream(aStream, *aValue, aManager, aDelayedStart);
   }
 
   return SerializeInputStream(aStream, *aOptionalValue, aManager,
                               aDelayedStart);
@@ -208,130 +148,88 @@ template <typename M>
 bool SerializeInputStreamParent(nsIInputStream* aStream, M* aManager,
                                 IPCStream* aValue,
                                 OptionalIPCStream* aOptionalValue,
                                 bool aDelayedStart) {
   MOZ_ASSERT(aStream);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(aValue || aOptionalValue);
 
-  // If a stream is known to be larger than 1MB, prefer sending it in chunks.
-  const uint64_t kTooLargeStream = 1024 * 1024;
-
   nsCOMPtr<nsIIPCSerializableInputStream> serializable =
       do_QueryInterface(aStream);
-  uint64_t expectedLength =
-      serializable ? serializable->ExpectedSerializedLength().valueOr(0) : 0;
 
-  if (serializable && expectedLength < kTooLargeStream) {
+  if (serializable) {
     if (aValue) {
-      return SerializeInputStreamWithFdsParent(serializable, *aValue, aManager);
+      return SerializeInputStreamWithFdsParent(serializable, *aValue,
+                                               aDelayedStart, aManager);
     }
 
     return SerializeInputStreamWithFdsParent(serializable, *aOptionalValue,
-                                             aManager);
+                                             aDelayedStart, aManager);
   }
 
   if (aValue) {
     return SerializeInputStream(aStream, *aValue, aManager, aDelayedStart);
   }
 
   return SerializeInputStream(aStream, *aOptionalValue, aManager,
                               aDelayedStart);
 }
 
-void CleanupIPCStream(IPCStream& aValue, bool aConsumedByIPC,
-                      bool aDelayedStart) {
-  if (aValue.type() == IPCStream::T__None) {
-    return;
+void ActivateAndCleanupIPCStream(IPCStream& aValue, bool aConsumedByIPC,
+                                 bool aDelayedStart) {
+  // Cleanup file descriptors if necessary
+  if (aValue.optionalFds().type() ==
+      OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
+    AutoTArray<FileDescriptor, 4> fds;
+
+    auto fdSetActor = static_cast<FileDescriptorSetChild*>(
+        aValue.optionalFds().get_PFileDescriptorSetChild());
+    MOZ_ASSERT(fdSetActor);
+
+    // FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
+    // unconditionally forget them here.  The fds themselves are auto-closed
+    // in ~FileDescriptor since they originated in this process.
+    fdSetActor->ForgetFileDescriptors(fds);
+
+    if (!aConsumedByIPC) {
+      Unused << FileDescriptorSetChild::Send__delete__(fdSetActor);
+    }
+
+  } else if (aValue.optionalFds().type() ==
+             OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
+    AutoTArray<FileDescriptor, 4> fds;
+
+    auto fdSetActor = static_cast<FileDescriptorSetParent*>(
+        aValue.optionalFds().get_PFileDescriptorSetParent());
+    MOZ_ASSERT(fdSetActor);
+
+    // FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
+    // unconditionally forget them here.  The fds themselves are auto-closed
+    // in ~FileDescriptor since they originated in this process.
+    fdSetActor->ForgetFileDescriptors(fds);
+
+    if (!aConsumedByIPC) {
+      Unused << FileDescriptorSetParent::Send__delete__(fdSetActor);
+    }
   }
 
-  if (aValue.type() == IPCStream::TInputStreamParamsWithFds) {
-    InputStreamParamsWithFds& streamWithFds =
-        aValue.get_InputStreamParamsWithFds();
-
-    // Cleanup file descriptors if necessary
-    if (streamWithFds.optionalFds().type() ==
-        OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
-      AutoTArray<FileDescriptor, 4> fds;
-
-      auto fdSetActor = static_cast<FileDescriptorSetChild*>(
-          streamWithFds.optionalFds().get_PFileDescriptorSetChild());
-      MOZ_ASSERT(fdSetActor);
-
-      // FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
-      // unconditionally forget them here.  The fds themselves are auto-closed
-      // in ~FileDescriptor since they originated in this process.
-      fdSetActor->ForgetFileDescriptors(fds);
-
-      if (!aConsumedByIPC) {
-        Unused << FileDescriptorSetChild::Send__delete__(fdSetActor);
-      }
-
-    } else if (streamWithFds.optionalFds().type() ==
-               OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
-      AutoTArray<FileDescriptor, 4> fds;
-
-      auto fdSetActor = static_cast<FileDescriptorSetParent*>(
-          streamWithFds.optionalFds().get_PFileDescriptorSetParent());
-      MOZ_ASSERT(fdSetActor);
-
-      // FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
-      // unconditionally forget them here.  The fds themselves are auto-closed
-      // in ~FileDescriptor since they originated in this process.
-      fdSetActor->ForgetFileDescriptors(fds);
-
-      if (!aConsumedByIPC) {
-        Unused << FileDescriptorSetParent::Send__delete__(fdSetActor);
-      }
-    }
-
-    return;
-  }
-
-  MOZ_ASSERT(aValue.type() == IPCStream::TIPCRemoteStream);
-  IPCRemoteStreamType& remoteInputStream =
-      aValue.get_IPCRemoteStream().stream();
-
-  IPCStreamSource* source = nullptr;
-  if (remoteInputStream.type() ==
-      IPCRemoteStreamType::TPChildToParentStreamChild) {
-    source = IPCStreamSource::Cast(
-        remoteInputStream.get_PChildToParentStreamChild());
-  } else {
-    MOZ_ASSERT(remoteInputStream.type() ==
-               IPCRemoteStreamType::TPParentToChildStreamParent);
-    source = IPCStreamSource::Cast(
-        remoteInputStream.get_PParentToChildStreamParent());
-  }
-
-  MOZ_ASSERT(source);
-
-  // If the source stream has not been taken to be sent to the other side, we
-  // can destroy it.
-  if (!aConsumedByIPC) {
-    source->StartDestroy();
-    return;
-  }
-
-  if (!aDelayedStart) {
-    // If we don't need to do a delayedStart, we start it now. Otherwise, the
-    // Start() will be called at the first use by the
-    // IPCStreamDestination::DelayedStartInputStream.
-    source->Start();
-  }
+  // Activate IPCRemoteStreamParams.
+  InputStreamHelper::PostSerializationActivation(aValue.stream(),
+                                                 aConsumedByIPC, aDelayedStart);
 }
 
-void CleanupIPCStream(OptionalIPCStream& aValue, bool aConsumedByIPC,
-                      bool aDelayedStart) {
+void ActivateAndCleanupIPCStream(OptionalIPCStream& aValue, bool aConsumedByIPC,
+                                 bool aDelayedStart) {
   if (aValue.type() == OptionalIPCStream::Tvoid_t) {
     return;
   }
 
-  CleanupIPCStream(aValue.get_IPCStream(), aConsumedByIPC, aDelayedStart);
+  ActivateAndCleanupIPCStream(aValue.get_IPCStream(), aConsumedByIPC,
+                              aDelayedStart);
 }
 
 // Returns false if the serialization should not proceed. This means that the
 // inputStream is null.
 bool NormalizeOptionalValue(nsIInputStream* aStream, IPCStream* aValue,
                             OptionalIPCStream* aOptionalValue) {
   if (aValue) {
     // if aStream is null, we will crash when serializing.
@@ -345,72 +243,47 @@ bool NormalizeOptionalValue(nsIInputStre
 
   *aOptionalValue = IPCStream();
   return true;
 }
 
 }  // anonymous namespace
 
 already_AddRefed<nsIInputStream> DeserializeIPCStream(const IPCStream& aValue) {
-  if (aValue.type() == IPCStream::TIPCRemoteStream) {
-    const IPCRemoteStream& remoteStream = aValue.get_IPCRemoteStream();
-    const IPCRemoteStreamType& remoteStreamType = remoteStream.stream();
-    IPCStreamDestination* destinationStream;
-
-    if (remoteStreamType.type() ==
-        IPCRemoteStreamType::TPChildToParentStreamParent) {
-      destinationStream = IPCStreamDestination::Cast(
-          remoteStreamType.get_PChildToParentStreamParent());
-    } else {
-      MOZ_ASSERT(remoteStreamType.type() ==
-                 IPCRemoteStreamType::TPParentToChildStreamChild);
-      destinationStream = IPCStreamDestination::Cast(
-          remoteStreamType.get_PParentToChildStreamChild());
-    }
-
-    destinationStream->SetDelayedStart(remoteStream.delayedStart());
-    destinationStream->SetLength(remoteStream.length());
-    return destinationStream->TakeReader();
-  }
-
   // Note, we explicitly do not support deserializing the PChildToParentStream
   // actor on the child side nor the PParentToChildStream actor on the parent
   // side.
-  MOZ_ASSERT(aValue.type() == IPCStream::TInputStreamParamsWithFds);
-
-  const InputStreamParamsWithFds& streamWithFds =
-      aValue.get_InputStreamParamsWithFds();
 
   AutoTArray<FileDescriptor, 4> fds;
-  if (streamWithFds.optionalFds().type() ==
+  if (aValue.optionalFds().type() ==
       OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
     auto fdSetActor = static_cast<FileDescriptorSetParent*>(
-        streamWithFds.optionalFds().get_PFileDescriptorSetParent());
+        aValue.optionalFds().get_PFileDescriptorSetParent());
     MOZ_ASSERT(fdSetActor);
 
     fdSetActor->ForgetFileDescriptors(fds);
     MOZ_ASSERT(!fds.IsEmpty());
 
     if (!FileDescriptorSetParent::Send__delete__(fdSetActor)) {
       // child process is gone, warn and allow actor to clean up normally
       NS_WARNING("Failed to delete fd set actor.");
     }
-  } else if (streamWithFds.optionalFds().type() ==
+  } else if (aValue.optionalFds().type() ==
              OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
     auto fdSetActor = static_cast<FileDescriptorSetChild*>(
-        streamWithFds.optionalFds().get_PFileDescriptorSetChild());
+        aValue.optionalFds().get_PFileDescriptorSetChild());
     MOZ_ASSERT(fdSetActor);
 
     fdSetActor->ForgetFileDescriptors(fds);
     MOZ_ASSERT(!fds.IsEmpty());
 
     Unused << FileDescriptorSetChild::Send__delete__(fdSetActor);
   }
 
-  return InputStreamHelper::DeserializeInputStream(streamWithFds.stream(), fds);
+  return InputStreamHelper::DeserializeInputStream(aValue.stream(), fds);
 }
 
 already_AddRefed<nsIInputStream> DeserializeIPCStream(
     const OptionalIPCStream& aValue) {
   if (aValue.type() == OptionalIPCStream::Tvoid_t) {
     return nullptr;
   }
 
@@ -438,19 +311,19 @@ AutoIPCStream::AutoIPCStream(OptionalIPC
       mTaken(false),
       mDelayedStart(aDelayedStart) {
   *mOptionalValue = void_t();
 }
 
 AutoIPCStream::~AutoIPCStream() {
   MOZ_ASSERT(mValue || mOptionalValue);
   if (mValue && IsSet()) {
-    CleanupIPCStream(*mValue, mTaken, mDelayedStart);
+    ActivateAndCleanupIPCStream(*mValue, mTaken, mDelayedStart);
   } else {
-    CleanupIPCStream(*mOptionalValue, mTaken, mDelayedStart);
+    ActivateAndCleanupIPCStream(*mOptionalValue, mTaken, mDelayedStart);
   }
 }
 
 bool AutoIPCStream::Serialize(nsIInputStream* aStream,
                               dom::nsIContentChild* aManager) {
   MOZ_ASSERT(aStream || !mValue);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mValue || mOptionalValue);
@@ -462,22 +335,16 @@ bool AutoIPCStream::Serialize(nsIInputSt
     return true;
   }
 
   if (!SerializeInputStreamChild(aStream, aManager, mValue, mOptionalValue,
                                  mDelayedStart)) {
     MOZ_CRASH("IPCStream creation failed!");
   }
 
-  if (mValue) {
-    AssertValidValueToTake(*mValue);
-  } else {
-    AssertValidValueToTake(*mOptionalValue);
-  }
-
   return true;
 }
 
 bool AutoIPCStream::Serialize(nsIInputStream* aStream,
                               PBackgroundChild* aManager) {
   MOZ_ASSERT(aStream || !mValue);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mValue || mOptionalValue);
@@ -489,22 +356,16 @@ bool AutoIPCStream::Serialize(nsIInputSt
     return true;
   }
 
   if (!SerializeInputStreamChild(aStream, aManager, mValue, mOptionalValue,
                                  mDelayedStart)) {
     MOZ_CRASH("IPCStream creation failed!");
   }
 
-  if (mValue) {
-    AssertValidValueToTake(*mValue);
-  } else {
-    AssertValidValueToTake(*mOptionalValue);
-  }
-
   return true;
 }
 
 bool AutoIPCStream::Serialize(nsIInputStream* aStream,
                               dom::nsIContentParent* aManager) {
   MOZ_ASSERT(aStream || !mValue);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mValue || mOptionalValue);
@@ -516,22 +377,16 @@ bool AutoIPCStream::Serialize(nsIInputSt
     return true;
   }
 
   if (!SerializeInputStreamParent(aStream, aManager, mValue, mOptionalValue,
                                   mDelayedStart)) {
     return false;
   }
 
-  if (mValue) {
-    AssertValidValueToTake(*mValue);
-  } else {
-    AssertValidValueToTake(*mOptionalValue);
-  }
-
   return true;
 }
 
 bool AutoIPCStream::Serialize(nsIInputStream* aStream,
                               PBackgroundParent* aManager) {
   MOZ_ASSERT(aStream || !mValue);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mValue || mOptionalValue);
@@ -543,59 +398,50 @@ bool AutoIPCStream::Serialize(nsIInputSt
     return true;
   }
 
   if (!SerializeInputStreamParent(aStream, aManager, mValue, mOptionalValue,
                                   mDelayedStart)) {
     return false;
   }
 
-  if (mValue) {
-    AssertValidValueToTake(*mValue);
-  } else {
-    AssertValidValueToTake(*mOptionalValue);
-  }
-
   return true;
 }
 
 bool AutoIPCStream::IsSet() const {
   MOZ_ASSERT(mValue || mOptionalValue);
   if (mValue) {
-    return mValue->type() != IPCStream::T__None;
+    return mValue->stream().type() != InputStreamParams::T__None;
   } else {
     return mOptionalValue->type() != OptionalIPCStream::Tvoid_t &&
-           mOptionalValue->get_IPCStream().type() != IPCStream::T__None;
+           mOptionalValue->get_IPCStream().stream().type() !=
+               InputStreamParams::T__None;
   }
 }
 
 IPCStream& AutoIPCStream::TakeValue() {
   MOZ_ASSERT(mValue || mOptionalValue);
   MOZ_ASSERT(!mTaken);
   MOZ_ASSERT(IsSet());
 
   mTaken = true;
 
   if (mValue) {
-    AssertValidValueToTake(*mValue);
     return *mValue;
   }
 
   IPCStream& value = mOptionalValue->get_IPCStream();
-
-  AssertValidValueToTake(value);
   return value;
 }
 
 OptionalIPCStream& AutoIPCStream::TakeOptionalValue() {
   MOZ_ASSERT(!mTaken);
   MOZ_ASSERT(!mValue);
   MOZ_ASSERT(mOptionalValue);
   mTaken = true;
-  AssertValidValueToTake(*mOptionalValue);
   return *mOptionalValue;
 }
 
 void IPDLParamTraits<nsIInputStream>::Write(IPC::Message* aMsg,
                                             IProtocol* aActor,
                                             nsIInputStream* aParam) {
   mozilla::ipc::AutoIPCStream autoStream;
   bool ok = false;
--- a/ipc/glue/InputStreamParams.ipdlh
+++ b/ipc/glue/InputStreamParams.ipdlh
@@ -1,14 +1,17 @@
 /* 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 ProtocolTypes;
 
+include protocol PChildToParentStream;
+include protocol PParentToChildStream;
+
 using struct mozilla::void_t
   from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace ipc {
 
 struct HeaderEntry
 {
@@ -47,26 +50,46 @@ struct SlicedInputStreamParams
 
 struct IPCBlobInputStreamParams
 {
   nsID id;
   uint64_t start;
   uint64_t length;
 };
 
+union IPCRemoteStreamType
+{
+  PChildToParentStream;
+  PParentToChildStream;
+};
+
+struct IPCRemoteStreamParams
+{
+  // If this is true, the stream will send data only when the first operation
+  // is done on the destination side. The benefit of this is that we do not
+  // send data if not needed. On the other hand, it could have a performance
+  // issue.
+  bool delayedStart;
+
+  IPCRemoteStreamType stream;
+
+  int64_t length;
+};
+
 union InputStreamParams
 {
   StringInputStreamParams;
   FileInputStreamParams;
   BufferedInputStreamParams;
   MIMEInputStreamParams;
   MultiplexInputStreamParams;
   SlicedInputStreamParams;
   IPCBlobInputStreamParams;
   InputStreamLengthWrapperParams;
+  IPCRemoteStreamParams;
 };
 
 union OptionalInputStreamParams
 {
   void_t;
   InputStreamParams;
 };
 
--- a/ipc/glue/InputStreamUtils.cpp
+++ b/ipc/glue/InputStreamUtils.cpp
@@ -7,78 +7,324 @@
 #include "InputStreamUtils.h"
 
 #include "nsIIPCSerializableInputStream.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ipc/IPCBlobInputStream.h"
 #include "mozilla/dom/ipc/IPCBlobInputStreamStorage.h"
+#include "mozilla/ipc/IPCStreamDestination.h"
+#include "mozilla/ipc/IPCStreamSource.h"
+#include "mozilla/InputStreamLengthHelper.h"
 #include "mozilla/SlicedInputStream.h"
 #include "mozilla/InputStreamLengthWrapper.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
+#include "nsIAsyncInputStream.h"
+#include "nsIAsyncOutputStream.h"
 #include "nsID.h"
+#include "nsIPipe.h"
 #include "nsIXULRuntime.h"
 #include "nsMIMEInputStream.h"
 #include "nsMultiplexInputStream.h"
 #include "nsNetCID.h"
+#include "nsStreamUtils.h"
 #include "nsStringStream.h"
 #include "nsXULAppAPI.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 namespace {
 
 NS_DEFINE_CID(kStringInputStreamCID, NS_STRINGINPUTSTREAM_CID);
 NS_DEFINE_CID(kFileInputStreamCID, NS_LOCALFILEINPUTSTREAM_CID);
 NS_DEFINE_CID(kBufferedInputStreamCID, NS_BUFFEREDINPUTSTREAM_CID);
 NS_DEFINE_CID(kMIMEInputStreamCID, NS_MIMEINPUTSTREAM_CID);
 NS_DEFINE_CID(kMultiplexInputStreamCID, NS_MULTIPLEXINPUTSTREAM_CID);
 
 }  // namespace
 
 namespace mozilla {
 namespace ipc {
 
-void InputStreamHelper::SerializeInputStream(
-    nsIInputStream* aInputStream, InputStreamParams& aParams,
-    nsTArray<FileDescriptor>& aFileDescriptors) {
+namespace {
+
+template <typename M>
+void SerializeInputStreamInternal(nsIInputStream* aInputStream,
+                                  InputStreamParams& aParams,
+                                  nsTArray<FileDescriptor>& aFileDescriptors,
+                                  bool aDelayedStart, M* aManager) {
   MOZ_ASSERT(aInputStream);
+  MOZ_ASSERT(aManager);
 
   nsCOMPtr<nsIIPCSerializableInputStream> serializable =
       do_QueryInterface(aInputStream);
   if (!serializable) {
     MOZ_CRASH("Input stream is not serializable!");
   }
 
-  serializable->Serialize(aParams, aFileDescriptors);
+  serializable->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);
 
   if (aParams.type() == InputStreamParams::T__None) {
     MOZ_CRASH("Serialize failed!");
   }
 }
 
+template <typename M>
+void SerializeInputStreamAsPipeInternal(nsIInputStream* aInputStream,
+                                        InputStreamParams& aParams,
+                                        bool aDelayedStart, M* aManager) {
+  MOZ_ASSERT(aInputStream);
+  MOZ_ASSERT(aManager);
+
+  // Let's try to take the length using InputStreamLengthHelper. If the length
+  // cannot be taken synchronously, and its length is needed, the stream needs
+  // to be fully copied in memory on the deserialization side.
+  int64_t length;
+  if (!InputStreamLengthHelper::GetSyncLength(aInputStream, &length)) {
+    length = -1;
+  }
+
+  // As a fallback, attempt to stream the data across using a IPCStream
+  // actor. For blocking streams, create a nonblocking pipe instead,
+  nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aInputStream);
+  if (!asyncStream) {
+    const uint32_t kBufferSize = 32768;  // matches IPCStream buffer size.
+    nsCOMPtr<nsIAsyncOutputStream> sink;
+    nsresult rv = NS_NewPipe2(getter_AddRefs(asyncStream), getter_AddRefs(sink),
+                              true, false, kBufferSize, UINT32_MAX);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+
+    nsCOMPtr<nsIEventTarget> target =
+        do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+
+    rv = NS_AsyncCopy(aInputStream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS,
+                      kBufferSize);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+  }
+
+  MOZ_ASSERT(asyncStream);
+
+  aParams = IPCRemoteStreamParams(
+      aDelayedStart, IPCStreamSource::Create(asyncStream, aManager), length);
+}
+
+}  // namespace
+
+void InputStreamHelper::SerializeInputStream(
+    nsIInputStream* aInputStream, InputStreamParams& aParams,
+    nsTArray<FileDescriptor>& aFileDescriptors, bool aDelayedStart,
+    nsIContentChild* aManager) {
+  SerializeInputStreamInternal(aInputStream, aParams, aFileDescriptors,
+                               aDelayedStart, aManager);
+}
+
+void InputStreamHelper::SerializeInputStream(
+    nsIInputStream* aInputStream, InputStreamParams& aParams,
+    nsTArray<FileDescriptor>& aFileDescriptors, bool aDelayedStart,
+    PBackgroundChild* aManager) {
+  SerializeInputStreamInternal(aInputStream, aParams, aFileDescriptors,
+                               aDelayedStart, aManager);
+}
+
+void InputStreamHelper::SerializeInputStream(
+    nsIInputStream* aInputStream, InputStreamParams& aParams,
+    nsTArray<FileDescriptor>& aFileDescriptors, bool aDelayedStart,
+    nsIContentParent* aManager) {
+  SerializeInputStreamInternal(aInputStream, aParams, aFileDescriptors,
+                               aDelayedStart, aManager);
+}
+
+void InputStreamHelper::SerializeInputStream(
+    nsIInputStream* aInputStream, InputStreamParams& aParams,
+    nsTArray<FileDescriptor>& aFileDescriptors, bool aDelayedStart,
+    PBackgroundParent* aManager) {
+  SerializeInputStreamInternal(aInputStream, aParams, aFileDescriptors,
+                               aDelayedStart, aManager);
+}
+
+void InputStreamHelper::SerializeInputStreamAsPipe(
+    nsIInputStream* aInputStream, InputStreamParams& aParams,
+    bool aDelayedStart, nsIContentChild* aManager) {
+  SerializeInputStreamAsPipeInternal(aInputStream, aParams, aDelayedStart,
+                                     aManager);
+}
+
+void InputStreamHelper::SerializeInputStreamAsPipe(nsIInputStream* aInputStream,
+                                                   InputStreamParams& aParams,
+                                                   bool aDelayedStart,
+                                                   PBackgroundChild* aManager) {
+  SerializeInputStreamAsPipeInternal(aInputStream, aParams, aDelayedStart,
+                                     aManager);
+}
+
+void InputStreamHelper::SerializeInputStreamAsPipe(
+    nsIInputStream* aInputStream, InputStreamParams& aParams,
+    bool aDelayedStart, nsIContentParent* aManager) {
+  SerializeInputStreamAsPipeInternal(aInputStream, aParams, aDelayedStart,
+                                     aManager);
+}
+
+void InputStreamHelper::SerializeInputStreamAsPipe(
+    nsIInputStream* aInputStream, InputStreamParams& aParams,
+    bool aDelayedStart, PBackgroundParent* aManager) {
+  SerializeInputStreamAsPipeInternal(aInputStream, aParams, aDelayedStart,
+                                     aManager);
+}
+
+void InputStreamHelper::PostSerializationActivation(InputStreamParams& aParams,
+                                                    bool aConsumedByIPC,
+                                                    bool aDelayedStart) {
+  switch (aParams.type()) {
+    case InputStreamParams::TBufferedInputStreamParams: {
+      BufferedInputStreamParams& params =
+          aParams.get_BufferedInputStreamParams();
+      InputStreamHelper::PostSerializationActivation(
+          params.optionalStream(), aConsumedByIPC, aDelayedStart);
+      return;
+    }
+
+    case InputStreamParams::TMIMEInputStreamParams: {
+      MIMEInputStreamParams& params = aParams.get_MIMEInputStreamParams();
+      InputStreamHelper::PostSerializationActivation(
+          params.optionalStream(), aConsumedByIPC, aDelayedStart);
+      return;
+    }
+
+    case InputStreamParams::TMultiplexInputStreamParams: {
+      MultiplexInputStreamParams& params =
+          aParams.get_MultiplexInputStreamParams();
+      for (InputStreamParams& subParams : params.streams()) {
+        InputStreamHelper::PostSerializationActivation(
+            subParams, aConsumedByIPC, aDelayedStart);
+      }
+      return;
+    }
+
+    case InputStreamParams::TSlicedInputStreamParams: {
+      SlicedInputStreamParams& params = aParams.get_SlicedInputStreamParams();
+      InputStreamHelper::PostSerializationActivation(
+          params.stream(), aConsumedByIPC, aDelayedStart);
+      return;
+    }
+
+    case InputStreamParams::TInputStreamLengthWrapperParams: {
+      InputStreamLengthWrapperParams& params =
+          aParams.get_InputStreamLengthWrapperParams();
+      InputStreamHelper::PostSerializationActivation(
+          params.stream(), aConsumedByIPC, aDelayedStart);
+      return;
+    }
+
+    case InputStreamParams::TIPCRemoteStreamParams: {
+      IPCRemoteStreamType& remoteInputStream =
+          aParams.get_IPCRemoteStreamParams().stream();
+
+      IPCStreamSource* source = nullptr;
+      if (remoteInputStream.type() ==
+          IPCRemoteStreamType::TPChildToParentStreamChild) {
+        source = IPCStreamSource::Cast(
+            remoteInputStream.get_PChildToParentStreamChild());
+      } else {
+        MOZ_ASSERT(remoteInputStream.type() ==
+                   IPCRemoteStreamType::TPParentToChildStreamParent);
+        source = IPCStreamSource::Cast(
+            remoteInputStream.get_PParentToChildStreamParent());
+      }
+
+      MOZ_ASSERT(source);
+
+      // If the source stream has not been taken to be sent to the other side,
+      // we can destroy it.
+      if (!aConsumedByIPC) {
+        source->StartDestroy();
+        return;
+      }
+
+      if (!aDelayedStart) {
+        // If we don't need to do a delayedStart, we start it now. Otherwise,
+        // the Start() will be called at the first use by the
+        // IPCStreamDestination::DelayedStartInputStream.
+        source->Start();
+      }
+
+      return;
+    }
+
+    case InputStreamParams::TStringInputStreamParams:
+      break;
+
+    case InputStreamParams::TFileInputStreamParams:
+      break;
+
+    case InputStreamParams::TIPCBlobInputStreamParams:
+      break;
+
+    default:
+      MOZ_CRASH(
+          "A new stream? Should decide if it must be processed recursively or "
+          "not.");
+  }
+}
+
+void InputStreamHelper::PostSerializationActivation(
+    OptionalInputStreamParams& aParams, bool aConsumedByIPC,
+    bool aDelayedStart) {
+  if (aParams.type() == OptionalInputStreamParams::TInputStreamParams) {
+    InputStreamHelper::PostSerializationActivation(
+        aParams.get_InputStreamParams(), aConsumedByIPC, aDelayedStart);
+  }
+}
+
 already_AddRefed<nsIInputStream> InputStreamHelper::DeserializeInputStream(
     const InputStreamParams& aParams,
     const nsTArray<FileDescriptor>& aFileDescriptors) {
-  nsCOMPtr<nsIInputStream> stream;
-  nsCOMPtr<nsIIPCSerializableInputStream> serializable;
-
   // IPCBlobInputStreams are not deserializable on the parent side.
   if (aParams.type() == InputStreamParams::TIPCBlobInputStreamParams) {
     MOZ_ASSERT(XRE_IsParentProcess());
+
+    nsCOMPtr<nsIInputStream> stream;
     IPCBlobInputStreamStorage::Get()->GetStream(
         aParams.get_IPCBlobInputStreamParams().id(),
         aParams.get_IPCBlobInputStreamParams().start(),
         aParams.get_IPCBlobInputStreamParams().length(),
         getter_AddRefs(stream));
     return stream.forget();
   }
 
+  if (aParams.type() == InputStreamParams::TIPCRemoteStreamParams) {
+    const IPCRemoteStreamParams& remoteStream =
+        aParams.get_IPCRemoteStreamParams();
+    const IPCRemoteStreamType& remoteStreamType = remoteStream.stream();
+    IPCStreamDestination* destinationStream;
+
+    if (remoteStreamType.type() ==
+        IPCRemoteStreamType::TPChildToParentStreamParent) {
+      destinationStream = IPCStreamDestination::Cast(
+          remoteStreamType.get_PChildToParentStreamParent());
+    } else {
+      MOZ_ASSERT(remoteStreamType.type() ==
+                 IPCRemoteStreamType::TPParentToChildStreamChild);
+      destinationStream = IPCStreamDestination::Cast(
+          remoteStreamType.get_PParentToChildStreamChild());
+    }
+
+    destinationStream->SetDelayedStart(remoteStream.delayedStart());
+    destinationStream->SetLength(remoteStream.length());
+    return destinationStream->TakeReader();
+  }
+
+  nsCOMPtr<nsIIPCSerializableInputStream> serializable;
+
   switch (aParams.type()) {
     case InputStreamParams::TStringInputStreamParams:
       serializable = do_CreateInstance(kStringInputStreamCID);
       break;
 
     case InputStreamParams::TFileInputStreamParams:
       serializable = do_CreateInstance(kFileInputStreamCID);
       break;
@@ -91,35 +337,35 @@ already_AddRefed<nsIInputStream> InputSt
       serializable = do_CreateInstance(kMIMEInputStreamCID);
       break;
 
     case InputStreamParams::TMultiplexInputStreamParams:
       serializable = do_CreateInstance(kMultiplexInputStreamCID);
       break;
 
     case InputStreamParams::TSlicedInputStreamParams:
-      serializable = new mozilla::SlicedInputStream();
+      serializable = new SlicedInputStream();
       break;
 
     case InputStreamParams::TInputStreamLengthWrapperParams:
-      serializable = new mozilla::InputStreamLengthWrapper();
+      serializable = new InputStreamLengthWrapper();
       break;
 
     default:
       MOZ_ASSERT(false, "Unknown params!");
       return nullptr;
   }
 
   MOZ_ASSERT(serializable);
 
   if (!serializable->Deserialize(aParams, aFileDescriptors)) {
     MOZ_ASSERT(false, "Deserialize failed!");
     return nullptr;
   }
 
-  stream = do_QueryInterface(serializable);
+  nsCOMPtr<nsIInputStream> stream = do_QueryInterface(serializable);
   MOZ_ASSERT(stream);
 
   return stream.forget();
 }
 
 }  // namespace ipc
 }  // namespace mozilla
--- a/ipc/glue/InputStreamUtils.h
+++ b/ipc/glue/InputStreamUtils.h
@@ -15,19 +15,77 @@
 namespace mozilla {
 namespace ipc {
 
 class FileDescriptor;
 
 // If you want to serialize an inputStream, please use AutoIPCStream.
 class InputStreamHelper {
  public:
+  // These 4 methods allow to serialize an inputStream into InputStreamParams.
+  // The manager is needed in case a stream needs to serialize itself as
+  // IPCRemoteStream.
+  // In case the stream wants to serialize itself as IPCRemoteStream, its
+  // content will be sent to the other side of the IPC pipe in chunks. This
+  // sending can start immediatelly or at the first read based on the value of
+  // |aDelayedStart|.
+  static void SerializeInputStream(nsIInputStream* aInputStream,
+                                   InputStreamParams& aParams,
+                                   nsTArray<FileDescriptor>& aFileDescriptors,
+                                   bool aDelayedStart,
+                                   mozilla::dom::nsIContentChild* aManager);
+
+  static void SerializeInputStream(nsIInputStream* aInputStream,
+                                   InputStreamParams& aParams,
+                                   nsTArray<FileDescriptor>& aFileDescriptors,
+                                   bool aDelayedStart,
+                                   PBackgroundChild* aManager);
+
+  static void SerializeInputStream(nsIInputStream* aInputStream,
+                                   InputStreamParams& aParams,
+                                   nsTArray<FileDescriptor>& aFileDescriptors,
+                                   bool aDelayedStart,
+                                   mozilla::dom::nsIContentParent* aManager);
+
   static void SerializeInputStream(nsIInputStream* aInputStream,
                                    InputStreamParams& aParams,
-                                   nsTArray<FileDescriptor>& aFileDescriptors);
+                                   nsTArray<FileDescriptor>& aFileDescriptors,
+                                   bool aDelayedStart,
+                                   PBackgroundParent* aManager);
+
+  // When a stream wants to serialize itself as IPCRemoteStream, it uses one of
+  // these methods.
+  static void SerializeInputStreamAsPipe(
+      nsIInputStream* aInputStream, InputStreamParams& aParams,
+      bool aDelayedStart, mozilla::dom::nsIContentChild* aManager);
+
+  static void SerializeInputStreamAsPipe(nsIInputStream* aInputStream,
+                                         InputStreamParams& aParams,
+                                         bool aDelayedStart,
+                                         PBackgroundChild* aManager);
+
+  static void SerializeInputStreamAsPipe(
+      nsIInputStream* aInputStream, InputStreamParams& aParams,
+      bool aDelayedStart, mozilla::dom::nsIContentParent* aManager);
+
+  static void SerializeInputStreamAsPipe(nsIInputStream* aInputStream,
+                                         InputStreamParams& aParams,
+                                         bool aDelayedStart,
+                                         PBackgroundParent* aManager);
+
+  // After the sending of the inputStream into the IPC pipe, some of the
+  // InputStreamParams data struct needs to be activated (IPCRemoteStream).
+  // These 2 methods do that.
+  static void PostSerializationActivation(InputStreamParams& aParams,
+                                          bool aConsumedByIPC,
+                                          bool aDelayedStart);
+
+  static void PostSerializationActivation(OptionalInputStreamParams& aParams,
+                                          bool aConsumedByIPC,
+                                          bool aDelayedStart);
 
   static already_AddRefed<nsIInputStream> DeserializeInputStream(
       const InputStreamParams& aParams,
       const nsTArray<FileDescriptor>& aFileDescriptors);
 };
 
 }  // namespace ipc
 }  // namespace mozilla
--- a/ipc/glue/nsIIPCSerializableInputStream.h
+++ b/ipc/glue/nsIIPCSerializableInputStream.h
@@ -8,93 +8,166 @@
 #define mozilla_ipc_nsIIPCSerializableInputStream_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "nsISupports.h"
 #include "nsTArrayForwardDeclare.h"
 
 namespace mozilla {
+
+namespace dom {
+
+class nsIContentChild;
+class nsIContentParent;
+
+}  // namespace dom
+
 namespace ipc {
 
 class FileDescriptor;
 class InputStreamParams;
+class PBackgroundChild;
+class PBackgroundParent;
 
 }  // namespace ipc
+
 }  // namespace mozilla
 
 #define NS_IIPCSERIALIZABLEINPUTSTREAM_IID           \
   {                                                  \
     0xb0211b14, 0xea6d, 0x40d4, {                    \
       0x87, 0xb5, 0x7b, 0xe3, 0xdf, 0xac, 0x09, 0xd1 \
     }                                                \
   }
 
 class NS_NO_VTABLE nsIIPCSerializableInputStream : public nsISupports {
  public:
   typedef nsTArray<mozilla::ipc::FileDescriptor> FileDescriptorArray;
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IIPCSERIALIZABLEINPUTSTREAM_IID)
 
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,
-                         FileDescriptorArray& aFileDescriptors) = 0;
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart,
+                         mozilla::dom::nsIContentChild* aManager) = 0;
+
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart,
+                         mozilla::ipc::PBackgroundChild* aManager) = 0;
+
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart,
+                         mozilla::dom::nsIContentParent* aManager) = 0;
+
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart,
+                         mozilla::ipc::PBackgroundParent* aManager) = 0;
 
   virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams,
                            const FileDescriptorArray& aFileDescriptors) = 0;
-
-  // The number of bytes that are expected to be written when this
-  // stream is serialized. A value of Some(N) indicates that N bytes
-  // will be written to the IPC buffer, and will be used to decide
-  // upon an optimal transmission mechanism. A value of Nothing
-  // indicates that either serializing this stream will not require
-  // serializing its contents (eg. a file-backed stream, or a stream
-  // backed by an IPC actor), or the length of the stream's contents
-  // cannot be determined.
-  virtual mozilla::Maybe<uint64_t> ExpectedSerializedLength() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream,
                               NS_IIPCSERIALIZABLEINPUTSTREAM_IID)
 
-#define NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM                      \
-  virtual void Serialize(mozilla::ipc::InputStreamParams&,         \
-                         FileDescriptorArray&) override;           \
-                                                                   \
-  virtual bool Deserialize(const mozilla::ipc::InputStreamParams&, \
-                           const FileDescriptorArray&) override;   \
-                                                                   \
-  virtual mozilla::Maybe<uint64_t> ExpectedSerializedLength() override;
+#define NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM                        \
+  virtual void Serialize(mozilla::ipc::InputStreamParams&,           \
+                         FileDescriptorArray&, bool,                 \
+                         mozilla::dom::nsIContentChild*) override;   \
+                                                                     \
+  virtual void Serialize(mozilla::ipc::InputStreamParams&,           \
+                         FileDescriptorArray&, bool,                 \
+                         mozilla::ipc::PBackgroundChild*) override;  \
+                                                                     \
+  virtual void Serialize(mozilla::ipc::InputStreamParams&,           \
+                         FileDescriptorArray&, bool,                 \
+                         mozilla::dom::nsIContentParent*) override;  \
+                                                                     \
+  virtual void Serialize(mozilla::ipc::InputStreamParams&,           \
+                         FileDescriptorArray&, bool,                 \
+                         mozilla::ipc::PBackgroundParent*) override; \
+                                                                     \
+  virtual bool Deserialize(const mozilla::ipc::InputStreamParams&,   \
+                           const FileDescriptorArray&) override;
 
-#define NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(_to)                      \
-  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,         \
-                         FileDescriptorArray& aFileDescriptors) override { \
-    _to Serialize(aParams, aFileDescriptors);                              \
-  }                                                                        \
-                                                                           \
-  virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams, \
-                           const FileDescriptorArray& aFileDescriptors)    \
-      override {                                                           \
-    return _to Deserialize(aParams, aFileDescriptors);                     \
-  }                                                                        \
-                                                                           \
-  virtual mozilla::Maybe<uint64_t> ExpectedSerializedLength() override {   \
-    return _to ExpectedSerializedLength();                                 \
+#define NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(_to)                          \
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
+                         FileDescriptorArray& aFileDescriptors,                \
+                         bool aDelayedStart,                                   \
+                         mozilla::dom::nsIContentChild* aManager) override {   \
+    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);         \
+  }                                                                            \
+                                                                               \
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
+                         FileDescriptorArray& aFileDescriptors,                \
+                         bool aDelayedStart,                                   \
+                         mozilla::ipc::PBackgroundChild* aManager) override {  \
+    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);         \
+  }                                                                            \
+                                                                               \
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
+                         FileDescriptorArray& aFileDescriptors,                \
+                         bool aDelayedStart,                                   \
+                         mozilla::dom::nsIContentParent* aManager) override {  \
+    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);         \
+  }                                                                            \
+                                                                               \
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
+                         FileDescriptorArray& aFileDescriptors,                \
+                         bool aDelayedStart,                                   \
+                         mozilla::ipc::PBackgroundParent* aManager) override { \
+    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);         \
+  }                                                                            \
+                                                                               \
+  virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams,     \
+                           const FileDescriptorArray& aFileDescriptors)        \
+      override {                                                               \
+    return _to Deserialize(aParams, aFileDescriptors);                         \
   }
 
-#define NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(_to)                 \
-  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,         \
-                         FileDescriptorArray& aFileDescriptors) override { \
-    if (_to) {                                                             \
-      _to->Serialize(aParams, aFileDescriptors);                           \
-    }                                                                      \
-  }                                                                        \
-                                                                           \
-  virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams, \
-                           const FileDescriptorArray& aFileDescriptors)    \
-      override {                                                           \
-    return _to ? _to->Deserialize(aParams, aFileDescriptors) : false;      \
-  }                                                                        \
-                                                                           \
-  virtual mozilla::Maybe<uint64_t> ExpectedSerializedLength() override {   \
-    return _to ? _to->ExpectedSerializedLength() : Nothing();              \
+#define NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(_to)                     \
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
+                         FileDescriptorArray& aFileDescriptors,                \
+                         bool aDelayedStart,                                   \
+                         mozilla::dom::nsIContentChild* aManager) override {   \
+    if (_to) {                                                                 \
+      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);      \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
+                         FileDescriptorArray& aFileDescriptors,                \
+                         bool aDelayedStart,                                   \
+                         mozilla::ipc::PBackgroundChild* aManager) override {  \
+    if (_to) {                                                                 \
+      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);      \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
+                         FileDescriptorArray& aFileDescriptors,                \
+                         bool aDelayedStart,                                   \
+                         mozilla::dom::nsIContentParent* aManager) override {  \
+    if (_to) {                                                                 \
+      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);      \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
+                         FileDescriptorArray& aFileDescriptors,                \
+                         bool aDelayedStart,                                   \
+                         mozilla::ipc::PBackgroundParent* aManager) override { \
+    if (_to) {                                                                 \
+      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);      \
+    }                                                                          \
+  }                                                                            \
+                                                                               \
+  virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams,     \
+                           const FileDescriptorArray& aFileDescriptors)        \
+      override {                                                               \
+    return _to ? _to->Deserialize(aParams, aFileDescriptors) : false;          \
   }
 
 #endif  // mozilla_ipc_nsIIPCSerializableInputStream_h
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -4998,17 +4998,17 @@ void GCRuntime::getNextSweepGroup() {
   }
 
   if (abortSweepAfterCurrentGroup) {
     for (SweepGroupZonesIter zone(rt); !zone.done(); zone.next()) {
       MOZ_ASSERT(!zone->gcNextGraphComponent);
       zone->setNeedsIncrementalBarrier(false);
       zone->changeGCState(Zone::MarkBlackOnly, Zone::NoGC);
       zone->arenas.unmarkPreMarkedFreeCells();
-      zone->gcGrayRoots().clearAndFree();
+      zone->gcGrayRoots().Clear();
     }
 
     for (SweepGroupCompartmentsIter comp(rt); !comp.done(); comp.next()) {
       ResetGrayList(comp);
     }
 
     abortSweepAfterCurrentGroup = false;
     currentSweepGroup = nullptr;
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2711,17 +2711,17 @@ void GCMarker::checkZone(void* p) {
   DebugOnly<Cell*> cell = static_cast<Cell*>(p);
   MOZ_ASSERT_IF(cell->isTenured(), cell->asTenured().zone()->isCollecting());
 }
 #endif
 
 size_t GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   size_t size = stack.sizeOfExcludingThis(mallocSizeOf);
   for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next()) {
-    size += zone->gcGrayRoots().sizeOfExcludingThis(mallocSizeOf);
+    size += zone->gcGrayRoots().SizeOfExcludingThis(mallocSizeOf);
   }
   return size;
 }
 
 /*** Tenuring Tracer ********************************************************/
 
 namespace js {
 template <typename T>
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -501,17 +501,17 @@ bool js::IsBufferGrayRootsTracer(JSTrace
 }
 #endif
 
 void js::gc::GCRuntime::bufferGrayRoots() {
   // Precondition: the state has been reset to "unused" after the last GC
   //               and the zone's buffers have been cleared.
   MOZ_ASSERT(grayBufferState == GrayBufferState::Unused);
   for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
-    MOZ_ASSERT(zone->gcGrayRoots().empty());
+    MOZ_ASSERT(zone->gcGrayRoots().IsEmpty());
   }
 
   BufferGrayRootsTracer grayBufferer(rt);
   if (JSTraceDataOp op = grayRootTracer.op) {
     (*op)(&grayBufferer, grayRootTracer.data);
   }
 
   // Propagate the failure flag from the marker to the runtime.
@@ -537,58 +537,57 @@ inline void BufferGrayRootsTracer::buffe
   Zone* zone = tenured->zoneFromAnyThread();
   if (zone->isCollectingFromAnyThread()) {
     // See the comment on SetMaybeAliveFlag to see why we only do this for
     // objects and scripts. We rely on gray root buffering for this to work,
     // but we only need to worry about uncollected dead compartments during
     // incremental GCs (when we do gray root buffering).
     SetMaybeAliveFlag(thing);
 
-    if (!zone->gcGrayRoots().append(tenured)) {
+    if (!zone->gcGrayRoots().Append(tenured)) {
       bufferingGrayRootsFailed = true;
     }
   }
 }
 
 void GCRuntime::markBufferedGrayRoots(JS::Zone* zone) {
   MOZ_ASSERT(grayBufferState == GrayBufferState::Okay);
   MOZ_ASSERT(zone->isGCMarkingBlackAndGray() || zone->isGCCompacting());
 
   auto& roots = zone->gcGrayRoots();
-  if (roots.empty()) {
+  if (roots.IsEmpty()) {
     return;
   }
 
-  for (size_t i = 0; i < roots.length(); i++) {
-    Cell* cell = roots[i];
+  for (auto iter = roots.Iter(); !iter.Done(); iter.Next()) {
+    Cell* cell = iter.Get();
 
     // Bug 1203273: Check for bad pointers on OSX and output diagnostics.
 #if defined(XP_DARWIN) && defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
     auto addr = uintptr_t(cell);
     if (addr < ChunkSize || addr % CellAlignBytes != 0) {
       MOZ_CRASH_UNSAFE_PRINTF(
-          "Bad GC thing pointer in gray root buffer: %p at index %zu of %zu, "
-          "address %p",
-          cell, i, roots.length(), &roots[i]);
+          "Bad GC thing pointer in gray root buffer: %p at address %p",
+          cell, &iter.Get());
     }
 #else
     MOZ_ASSERT(IsCellPointerValid(cell));
 #endif
 
     TraceManuallyBarrieredGenericPointerEdge(&marker, &cell,
                                              "buffered gray root");
   }
 }
 
 void GCRuntime::resetBufferedGrayRoots() const {
   MOZ_ASSERT(
       grayBufferState != GrayBufferState::Okay,
       "Do not clear the gray buffers unless we are Failed or becoming Unused");
   for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
-    zone->gcGrayRoots().clearAndFree();
+    zone->gcGrayRoots().Clear();
   }
 }
 
 JS_PUBLIC_API void JS::AddPersistentRoot(JS::RootingContext* cx, RootKind kind,
                                          PersistentRooted<void*>* root) {
   static_cast<JSContext*>(cx)->runtime()->heapRoots.ref()[kind].insertBack(
       root);
 }
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -4,16 +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/. */
 
 #ifndef gc_Zone_h
 #define gc_Zone_h
 
 #include "mozilla/Atomics.h"
 #include "mozilla/HashFunctions.h"
+#include "mozilla/SegmentedVector.h"
 
 #include "gc/FindSCCs.h"
 #include "js/GCHashTable.h"
 #include "vm/MallocProvider.h"
 #include "vm/Runtime.h"
 #include "vm/TypeInference.h"
 
 namespace js {
@@ -370,17 +371,19 @@ class Zone : public JS::shadow::Zone,
  private:
   // The set of compartments in this zone.
   js::MainThreadOrGCTaskData<CompartmentVector> compartments_;
 
  public:
   CompartmentVector& compartments() { return compartments_.ref(); }
 
   // This zone's gray roots.
-  typedef js::Vector<js::gc::Cell*, 0, js::SystemAllocPolicy> GrayRootVector;
+  using GrayRootVector = mozilla::SegmentedVector<js::gc::Cell*,
+                                                  1024 * sizeof(js::gc::Cell*),
+                                                  js::SystemAllocPolicy>;
 
  private:
   js::ZoneOrGCTaskData<GrayRootVector> gcGrayRoots_;
 
  public:
   GrayRootVector& gcGrayRoots() { return gcGrayRoots_.ref(); }
 
   // This zone's weak edges found via graph traversal during marking,
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -382,17 +382,18 @@ static UniqueMapping MapFile(PRFileDesc*
   PR_CloseFileMap(map);
   return UniqueMapping(memory, MemUnmap(info->size));
 }
 
 RefPtr<JS::WasmModule> wasm::DeserializeModule(PRFileDesc* bytecodeFile,
                                                UniqueChars filename,
                                                unsigned line) {
   // We have to compile new code here so if we're fundamentally unable to
-  // compile, we have to fail.
+  // compile, we have to fail. If you change this code, update the
+  // MutableCompileArgs setting below.
   if (!BaselineCanCompile() && !IonCanCompile()) {
     return nullptr;
   }
 
   PRFileInfo bytecodeInfo;
   UniqueMapping bytecodeMapping = MapFile(bytecodeFile, &bytecodeInfo);
   if (!bytecodeMapping) {
     return nullptr;
@@ -419,19 +420,21 @@ RefPtr<JS::WasmModule> wasm::Deserialize
   // the JSContext that originated the call that caused this deserialization
   // attempt to happen. We don't have that context here, so we assume that
   // shared memory is enabled; we will catch a wrong assumption later, during
   // instantiation.
   //
   // (We would prefer to store this value with the Assumptions when
   // serializing, and for the caller of the deserialization machinery to
   // provide the value from the originating context.)
+  //
+  // Note this is guarded at the top of this function.
 
-  args->ionEnabled = true;
-  args->baselineEnabled = true;
+  args->ionEnabled = IonCanCompile();
+  args->baselineEnabled = BaselineCanCompile();
   args->sharedMemoryEnabled = true;
 
   UniqueChars error;
   UniqueCharsVector warnings;
   SharedModule module = CompileBuffer(*args, *bytecode, &error, &warnings);
   if (!module) {
     return nullptr;
   }
--- a/layout/reftests/first-line/reftest.list
+++ b/layout/reftests/first-line/reftest.list
@@ -27,17 +27,17 @@ load stress-10.html # crash test
 
 == border-not-apply.html border-not-apply-ref.html
 == 287088-1.html 287088-1-ref.html
 == 287088-2.html 287088-2-ref.html
 == 403177-1.html 403177-1-ref.html
 == 469227-2.html 469227-2-ref.html
 == 469227-3.html 469227-3-ref.html
 
-== restyle-inside-first-line.html restyle-inside-first-line-ref.html
+random == restyle-inside-first-line.html restyle-inside-first-line-ref.html # bug 1523134
 == font-styles.html font-styles-ref.html
 fuzzy-if(OSX==1010,0-1,0-2) == font-styles-nooverflow.html font-styles-ref.html
 
 == ib-split-1.html ib-split-1-ref.html
 
 == first-line-in-columnset-1.html first-line-in-columnset-1-ref.html
 
 == insertion-in-first-line-1.html insertion-in-first-line-ref.html
--- a/mobile/android/tests/browser/robocop/testTrackingProtection.js
+++ b/mobile/android/tests/browser/robocop/testTrackingProtection.js
@@ -4,16 +4,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/Messaging.jsm");
 
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
+
 function promiseLoadEvent(browser, url, eventType = "load", runBeforeLoad) {
   return new Promise((resolve, reject) => {
     do_print("Wait browser event: " + eventType);
 
     function handle(event) {
       if (event.target != browser.contentDocument || event.target.location.href == "about:blank" || (url && event.target.location.href != url)) {
         do_print("Skipping spurious '" + eventType + "' event" + " for " + event.target.location.href);
         return;
@@ -76,16 +78,18 @@ function doUpdate() {
   });
 }
 
 var BrowserApp = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
 
 // Tests the tracking protection UI in private browsing. By default, tracking protection is
 // enabled in private browsing ("privacy.trackingprotection.pbmode.enabled").
 add_task(async function test_tracking_pb() {
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
+
   // Load a blank page
   let browser = BrowserApp.addTab("about:blank", { selected: true, parentId: BrowserApp.selectedTab.id, isPrivate: true }).browser;
   await new Promise((resolve, reject) => {
     browser.addEventListener("load", function(event) {
       Services.tm.dispatchToMainThread(resolve);
     }, {capture: true, once: true});
   });
 
@@ -155,9 +159,13 @@ add_task(async function test_tracking_no
   // Enable tracking protection in normal tabs
   Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
 
   // Point tab to a test page containing tracking elements (tracking protection UI *should* be shown)
   await promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_bad.html");
   EventDispatcher.instance.sendRequest({ type: "Test:Expected", expected: "tracking_content_blocked" });
 });
 
+add_task(async function cleanup() {
+  Services.prefs.clearUserPref(DTSCBN_PREF);
+});
+
 run_next_test();
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1601,17 +1601,21 @@ pref("javascript.options.spectre.jit_to_
 
 // Streams API
 pref("javascript.options.streams", true);
 
 // BigInt API
 pref("javascript.options.bigint", false);
 
 // Dynamic module import.
+#ifdef NIGHTLY_BUILD
+pref("javascript.options.dynamicImport", true);
+#else
 pref("javascript.options.dynamicImport", false);
+#endif
 
 // advanced prefs
 pref("advanced.mailftp",                    false);
 pref("image.animation_mode",                "normal");
 
 // Same-origin policy for file URIs, "false" is traditional
 pref("security.fileuri.strict_origin_policy", true);
 
--- a/netwerk/base/PartiallySeekableInputStream.cpp
+++ b/netwerk/base/PartiallySeekableInputStream.cpp
@@ -275,39 +275,59 @@ PartiallySeekableInputStream::OnInputStr
   MOZ_ASSERT(callback);
   return callback->OnInputStreamReady(this);
 }
 
 // nsIIPCSerializableInputStream
 
 void PartiallySeekableInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
-    FileDescriptorArray& aFileDescriptors) {
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void PartiallySeekableInputStream::Serialize(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::ipc::PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void PartiallySeekableInputStream::Serialize(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void PartiallySeekableInputStream::Serialize(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::ipc::PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+template <typename M>
+void PartiallySeekableInputStream::SerializeInternal(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart, M* aManager) {
   MOZ_ASSERT(mWeakIPCSerializableInputStream);
   MOZ_DIAGNOSTIC_ASSERT(mCachedBuffer.IsEmpty());
-  mozilla::ipc::InputStreamHelper::SerializeInputStream(mInputStream, aParams,
-                                                        aFileDescriptors);
+  mozilla::ipc::InputStreamHelper::SerializeInputStream(
+      mInputStream, aParams, aFileDescriptors, aDelayedStart, aManager);
 }
 
 bool PartiallySeekableInputStream::Deserialize(
     const mozilla::ipc::InputStreamParams& aParams,
     const FileDescriptorArray& aFileDescriptors) {
   MOZ_CRASH("This method should never be called!");
   return false;
 }
 
-mozilla::Maybe<uint64_t>
-PartiallySeekableInputStream::ExpectedSerializedLength() {
-  if (!mWeakIPCSerializableInputStream) {
-    return mozilla::Nothing();
-  }
-
-  return mWeakIPCSerializableInputStream->ExpectedSerializedLength();
-}
-
 // nsISeekableStream
 
 NS_IMETHODIMP
 PartiallySeekableInputStream::Seek(int32_t aWhence, int64_t aOffset) {
   if (mClosed) {
     return NS_BASE_STREAM_CLOSED;
   }
 
--- a/netwerk/base/PartiallySeekableInputStream.h
+++ b/netwerk/base/PartiallySeekableInputStream.h
@@ -50,16 +50,21 @@ class PartiallySeekableInputStream final
   PartiallySeekableInputStream(
       already_AddRefed<nsIInputStream> aClonedBaseStream,
       PartiallySeekableInputStream* aClonedFrom);
 
   ~PartiallySeekableInputStream() = default;
 
   void Init();
 
+  template <typename M>
+  void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart, M* aManager);
+
   nsCOMPtr<nsIInputStream> mInputStream;
 
   // Raw pointers because these are just QI of mInputStream.
   nsICloneableInputStream* mWeakCloneableInputStream;
   nsIIPCSerializableInputStream* mWeakIPCSerializableInputStream;
   nsIAsyncInputStream* mWeakAsyncInputStream;
   nsIInputStreamLength* mWeakInputStreamLength;
   nsIAsyncInputStreamLength* mWeakAsyncInputStreamLength;
--- a/netwerk/base/nsBufferedStreams.cpp
+++ b/netwerk/base/nsBufferedStreams.cpp
@@ -585,26 +585,55 @@ nsBufferedInputStream::GetUnbufferedStre
   mFillPoint = mCursor = 0;
 
   *aStream = mStream;
   NS_IF_ADDREF(*aStream);
   return NS_OK;
 }
 
 void nsBufferedInputStream::Serialize(InputStreamParams& aParams,
-                                      FileDescriptorArray& aFileDescriptors) {
+                                      FileDescriptorArray& aFileDescriptors,
+                                      bool aDelayedStart,
+                                      mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void nsBufferedInputStream::Serialize(InputStreamParams& aParams,
+                                      FileDescriptorArray& aFileDescriptors,
+                                      bool aDelayedStart,
+                                      PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void nsBufferedInputStream::Serialize(
+    InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
+    bool aDelayedStart, mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void nsBufferedInputStream::Serialize(InputStreamParams& aParams,
+                                      FileDescriptorArray& aFileDescriptors,
+                                      bool aDelayedStart,
+                                      PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+template <typename M>
+void nsBufferedInputStream::SerializeInternal(
+    InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
+    bool aDelayedStart, M* aManager) {
   BufferedInputStreamParams params;
 
   if (mStream) {
     nsCOMPtr<nsIInputStream> stream = do_QueryInterface(mStream);
     MOZ_ASSERT(stream);
 
     InputStreamParams wrappedParams;
-    InputStreamHelper::SerializeInputStream(stream, wrappedParams,
-                                            aFileDescriptors);
+    InputStreamHelper::SerializeInputStream(
+        stream, wrappedParams, aFileDescriptors, aDelayedStart, aManager);
 
     params.optionalStream() = wrappedParams;
   } else {
     params.optionalStream() = mozilla::void_t();
   }
 
   params.bufferSize() = mBufferSize;
 
@@ -637,24 +666,16 @@ bool nsBufferedInputStream::Deserialize(
   }
 
   nsresult rv = Init(stream, params.bufferSize());
   NS_ENSURE_SUCCESS(rv, false);
 
   return true;
 }
 
-Maybe<uint64_t> nsBufferedInputStream::ExpectedSerializedLength() {
-  nsCOMPtr<nsIIPCSerializableInputStream> stream = do_QueryInterface(mStream);
-  if (stream) {
-    return stream->ExpectedSerializedLength();
-  }
-  return Nothing();
-}
-
 NS_IMETHODIMP
 nsBufferedInputStream::CloseWithStatus(nsresult aStatus) { return Close(); }
 
 NS_IMETHODIMP
 nsBufferedInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
                                  uint32_t aFlags, uint32_t aRequestedCount,
                                  nsIEventTarget* aEventTarget) {
   nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mStream);
--- a/netwerk/base/nsBufferedStreams.h
+++ b/netwerk/base/nsBufferedStreams.h
@@ -90,16 +90,21 @@ class nsBufferedInputStream final : publ
 
   static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
 
   nsIInputStream* Source() { return (nsIInputStream*)mStream; }
 
  protected:
   virtual ~nsBufferedInputStream() = default;
 
+  template <typename M>
+  void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart, M* aManager);
+
   NS_IMETHOD Fill() override;
   NS_IMETHOD Flush() override { return NS_OK; }  // no-op for input streams
 
   mozilla::Mutex mMutex;
 
   // This value is protected by mutex.
   nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
 
--- a/netwerk/base/nsFileStreams.cpp
+++ b/netwerk/base/nsFileStreams.cpp
@@ -531,17 +531,45 @@ nsFileInputStream::Tell(int64_t* aResult
 }
 
 NS_IMETHODIMP
 nsFileInputStream::Available(uint64_t* aResult) {
   return nsFileStreamBase::Available(aResult);
 }
 
 void nsFileInputStream::Serialize(InputStreamParams& aParams,
-                                  FileDescriptorArray& aFileDescriptors) {
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors);
+}
+
+void nsFileInputStream::Serialize(InputStreamParams& aParams,
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors);
+}
+
+void nsFileInputStream::Serialize(InputStreamParams& aParams,
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors);
+}
+
+void nsFileInputStream::Serialize(InputStreamParams& aParams,
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors);
+}
+
+void nsFileInputStream::SerializeInternal(
+    InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors) {
   FileInputStreamParams params;
 
   if (NS_SUCCEEDED(DoPendingOpen())) {
     MOZ_ASSERT(mFD);
     FileHandleType fd = FileHandleType(PR_FileDesc2NativeHandle(mFD));
     NS_ASSERTION(fd, "This should never be null!");
 
     DebugOnly<FileDescriptor*> dbgFD = aFileDescriptors.AppendElement(fd);
@@ -621,20 +649,16 @@ bool nsFileInputStream::Deserialize(
     mBehaviorFlags &= ~nsIFileInputStream::REOPEN_ON_REWIND;
   }
 
   mIOFlags = params.ioFlags();
 
   return true;
 }
 
-Maybe<uint64_t> nsFileInputStream::ExpectedSerializedLength() {
-  return Nothing();
-}
-
 bool nsFileInputStream::IsCloneable() const {
   // This inputStream is cloneable only if has been created using Init() and
   // it owns a nsIFile. This is not true when it is deserialized from IPC.
   return XRE_IsParentProcess() && mFile;
 }
 
 NS_IMETHODIMP
 nsFileInputStream::GetCloneable(bool* aCloneable) {
--- a/netwerk/base/nsFileStreams.h
+++ b/netwerk/base/nsFileStreams.h
@@ -148,16 +148,19 @@ class nsFileInputStream : public nsFileS
   nsFileInputStream()
       : mLineBuffer(nullptr), mIOFlags(0), mPerm(0), mCachedPosition(0) {}
 
   static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
 
  protected:
   virtual ~nsFileInputStream() = default;
 
+  void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors);
+
   nsresult SeekInternal(int32_t aWhence, int64_t aOffset,
                         bool aClearBuf = true);
 
   nsAutoPtr<nsLineBuffer<char> > mLineBuffer;
 
   /**
    * The file being opened.
    */
--- a/netwerk/base/nsMIMEInputStream.cpp
+++ b/netwerk/base/nsMIMEInputStream.cpp
@@ -53,16 +53,21 @@ class nsMIMEInputStream : public nsIMIME
   NS_DECL_NSIINPUTSTREAMLENGTH
   NS_DECL_NSIASYNCINPUTSTREAMLENGTH
   NS_DECL_NSIINPUTSTREAMLENGTHCALLBACK
   NS_DECL_NSICLONEABLEINPUTSTREAM
 
  private:
   void InitStreams();
 
+  template <typename M>
+  void SerializeInternal(InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart, M* aManager);
+
   struct MOZ_STACK_CLASS ReadSegmentsState {
     nsCOMPtr<nsIInputStream> mThisStream;
     nsWriteSegmentFun mWriter;
     void* mClosure;
   };
   static nsresult ReadSegCb(nsIInputStream* aIn, void* aClosure,
                             const char* aFromRawSegment, uint32_t aToOffset,
                             uint32_t aCount, uint32_t* aWriteCount);
@@ -325,23 +330,53 @@ nsresult nsMIMEInputStreamConstructor(ns
 
   RefPtr<nsMIMEInputStream> inst = new nsMIMEInputStream();
   if (!inst) return NS_ERROR_OUT_OF_MEMORY;
 
   return inst->QueryInterface(iid, result);
 }
 
 void nsMIMEInputStream::Serialize(InputStreamParams& aParams,
-                                  FileDescriptorArray& aFileDescriptors) {
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void nsMIMEInputStream::Serialize(InputStreamParams& aParams,
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void nsMIMEInputStream::Serialize(InputStreamParams& aParams,
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void nsMIMEInputStream::Serialize(InputStreamParams& aParams,
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+template <typename M>
+void nsMIMEInputStream::SerializeInternal(InputStreamParams& aParams,
+                                          FileDescriptorArray& aFileDescriptors,
+                                          bool aDelayedStart, M* aManager) {
   MIMEInputStreamParams params;
 
   if (mStream) {
     InputStreamParams wrappedParams;
-    InputStreamHelper::SerializeInputStream(mStream, wrappedParams,
-                                            aFileDescriptors);
+    InputStreamHelper::SerializeInputStream(
+        mStream, wrappedParams, aFileDescriptors, aDelayedStart, aManager);
 
     NS_ASSERTION(wrappedParams.type() != InputStreamParams::T__None,
                  "Wrapped stream failed to serialize!");
 
     params.optionalStream() = wrappedParams;
   } else {
     params.optionalStream() = mozilla::void_t();
   }
@@ -379,22 +414,16 @@ bool nsMIMEInputStream::Deserialize(
   } else {
     NS_ASSERTION(wrappedParams.type() == OptionalInputStreamParams::Tvoid_t,
                  "Unknown type for OptionalInputStreamParams!");
   }
 
   return true;
 }
 
-Maybe<uint64_t> nsMIMEInputStream::ExpectedSerializedLength() {
-  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
-      do_QueryInterface(mStream);
-  return serializable ? serializable->ExpectedSerializedLength() : Nothing();
-}
-
 NS_IMETHODIMP
 nsMIMEInputStream::Length(int64_t* aLength) {
   nsCOMPtr<nsIInputStreamLength> stream = do_QueryInterface(mStream);
   if (NS_WARN_IF(!stream)) {
     return NS_ERROR_FAILURE;
   }
 
   return stream->Length(aLength);
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_42_BETA2
+NSS_3_42_RTM
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -17,22 +17,22 @@
 
 /*
  * NSS's major version, minor version, patch level, build number, and whether
  * this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define NSS_VERSION "3.42" _NSS_CUSTOMIZED " Beta"
+#define NSS_VERSION "3.42" _NSS_CUSTOMIZED
 #define NSS_VMAJOR 3
 #define NSS_VMINOR 42
 #define NSS_VPATCH 0
 #define NSS_VBUILD 0
-#define NSS_BETA PR_TRUE
+#define NSS_BETA PR_FALSE
 
 #ifndef RC_INVOKED
 
 #include "seccomon.h"
 
 typedef struct NSSInitParametersStr NSSInitParameters;
 
 /*
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -12,16 +12,16 @@
 
 /*
  * Softoken's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define SOFTOKEN_VERSION "3.42" SOFTOKEN_ECC_STRING " Beta"
+#define SOFTOKEN_VERSION "3.42" SOFTOKEN_ECC_STRING
 #define SOFTOKEN_VMAJOR 3
 #define SOFTOKEN_VMINOR 42
 #define SOFTOKEN_VPATCH 0
 #define SOFTOKEN_VBUILD 0
-#define SOFTOKEN_BETA PR_TRUE
+#define SOFTOKEN_BETA PR_FALSE
 
 #endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -14,22 +14,22 @@
 
 /*
  * NSS utilities's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
  */
-#define NSSUTIL_VERSION "3.42 Beta"
+#define NSSUTIL_VERSION "3.42"
 #define NSSUTIL_VMAJOR 3
 #define NSSUTIL_VMINOR 42
 #define NSSUTIL_VPATCH 0
 #define NSSUTIL_VBUILD 0
-#define NSSUTIL_BETA PR_TRUE
+#define NSSUTIL_BETA PR_FALSE
 
 SEC_BEGIN_PROTOS
 
 /*
  * Returns a const string of the UTIL library version.
  */
 extern const char *NSSUTIL_GetVersion(void);
 
--- a/testing/talos/talos.json
+++ b/testing/talos/talos.json
@@ -64,28 +64,28 @@
             "tests": ["tp5n"],
             "pagesets_name": "tp5n.zip",
             "talos_options": [
                 "--xperf_path",
                 "\"c:/Program Files (x86)/Windows Kits/10/Windows Performance Toolkit/xperf.exe\""
             ]
         },
         "tp6-e10s": {
-            "tests": ["tp6_google", "tp6_youtube", "tp6_amazon", "tp6_facebook"],
+            "tests": ["tp6_youtube", "tp6_amazon", "tp6_facebook"],
             "mitmproxy_release_bin_osx": "mitmproxy-2.0.2-osx.tar.gz",
             "mitmproxy_release_bin_linux64": "mitmproxy-2.0.2-linux.tar.gz",
             "mitmproxy_recording_set": "mitmproxy-recording-set-win10.zip",
             "talos_options": [
                 "--mitmproxy",
                 "mitmproxy-recording-google.mp mitmproxy-recording-youtube.mp mitmproxy-recording-amazon.mp mitmproxy-recording-facebook.mp",
                 "--firstNonBlankPaint"
             ]
         },
         "tp6-stylo-threads-e10s": {
-            "tests": ["tp6_google", "tp6_youtube", "tp6_amazon", "tp6_facebook"],
+            "tests": ["tp6_youtube", "tp6_amazon", "tp6_facebook"],
             "mitmproxy_release_bin_osx": "mitmproxy-2.0.2-osx.tar.gz",
             "mitmproxy_release_bin_linux64": "mitmproxy-2.0.2-linux.tar.gz",
             "mitmproxy_recording_set": "mitmproxy-recording-set-win10.zip",
             "talos_options": [
                 "--stylo-threads=1",
                 "--mitmproxy",
                 "mitmproxy-recording-google.mp mitmproxy-recording-youtube.mp mitmproxy-recording-amazon.mp mitmproxy-recording-facebook.mp",
                 "--firstNonBlankPaint"
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/backgrounds/background-root-010.xht.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[background-root-010.xht]
-  disabled:
-    if webrender: bug 1453935
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/backgrounds/background-root-016.xht.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[background-root-016.xht]
-  disabled:
-    if webrender: bug 1453935
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/html/browsers/origin/relaxing-the-same-origin-restriction/__dir__.ini
@@ -0,0 +1,1 @@
+prefs: [dom.security.featurePolicy.enabled:true]
--- a/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
@@ -205,17 +205,20 @@ function testOnWindow(aTestData) {
       await BrowserTestUtils.waitForContentEvent(browser, "DOMContentLoaded");
       checkResults(aTestData, expected);
       win.close();
       resolve();
     })();
   });
 }
 SpecialPowers.pushPrefEnv(
-  {"set": [["browser.safebrowsing.phishing.enabled", true]]},
+  {"set": [
+    ["browser.safebrowsing.phishing.enabled", true],
+    ["dom.testing.sync-content-blocking-notifications", true],
+  ]},
   test);
 
 function test() {
   (async function() {
     await classifierHelper.waitForInit();
 
     for (let testData of testDatas) {
       await setupTestData(testData);
--- a/widget/cocoa/nsMacDockSupport.mm
+++ b/widget/cocoa/nsMacDockSupport.mm
@@ -128,17 +128,17 @@ bool nsMacDockSupport::InitProgress() {
     mAppIcon = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
     mProgressBackground = [mAppIcon copyWithZone:nil];
     mTheme = new nsNativeThemeCocoa();
 
     NSSize sz = [mProgressBackground size];
     mProgressBounds =
         CGRectMake(sz.width * 1 / 32, sz.height * 3 / 32, sz.width * 30 / 32, sz.height * 4 / 32);
     [mProgressBackground lockFocus];
-    [[NSColor whiteColor] set];
+    [[NSColor clearColor] set];
     NSRectFill(NSRectFromCGRect(mProgressBounds));
     [mProgressBackground unlockFocus];
   }
   return true;
 }
 
 nsresult nsMacDockSupport::RedrawIcon() {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
--- a/xpcom/io/InputStreamLengthWrapper.cpp
+++ b/xpcom/io/InputStreamLengthWrapper.cpp
@@ -253,23 +253,52 @@ InputStreamLengthWrapper::OnInputStreamR
   MOZ_ASSERT(callback);
   return callback->OnInputStreamReady(this);
 }
 
 // nsIIPCSerializableInputStream
 
 void InputStreamLengthWrapper::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
-    FileDescriptorArray& aFileDescriptors) {
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void InputStreamLengthWrapper::Serialize(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::ipc::PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void InputStreamLengthWrapper::Serialize(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void InputStreamLengthWrapper::Serialize(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::ipc::PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+template <typename M>
+void InputStreamLengthWrapper::SerializeInternal(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart, M* aManager) {
   MOZ_ASSERT(mInputStream);
   MOZ_ASSERT(mWeakIPCSerializableInputStream);
 
   InputStreamLengthWrapperParams params;
-  InputStreamHelper::SerializeInputStream(mInputStream, params.stream(),
-                                          aFileDescriptors);
+  InputStreamHelper::SerializeInputStream(
+      mInputStream, params.stream(), aFileDescriptors, aDelayedStart, aManager);
   params.length() = mLength;
   params.consumed() = mConsumed;
 
   aParams = params;
 }
 
 bool InputStreamLengthWrapper::Deserialize(
     const mozilla::ipc::InputStreamParams& aParams,
@@ -295,24 +324,16 @@ bool InputStreamLengthWrapper::Deseriali
   SetSourceStream(stream.forget());
 
   mLength = params.length();
   mConsumed = params.consumed();
 
   return true;
 }
 
-mozilla::Maybe<uint64_t> InputStreamLengthWrapper::ExpectedSerializedLength() {
-  if (!mInputStream || !mWeakIPCSerializableInputStream) {
-    return mozilla::Nothing();
-  }
-
-  return mWeakIPCSerializableInputStream->ExpectedSerializedLength();
-}
-
 // nsISeekableStream
 
 NS_IMETHODIMP
 InputStreamLengthWrapper::Seek(int32_t aWhence, int64_t aOffset) {
   NS_ENSURE_STATE(mInputStream);
   NS_ENSURE_STATE(mWeakSeekableInputStream);
 
   mConsumed = true;
--- a/xpcom/io/InputStreamLengthWrapper.h
+++ b/xpcom/io/InputStreamLengthWrapper.h
@@ -54,16 +54,21 @@ class InputStreamLengthWrapper final : p
                            int64_t aLength);
 
   // This CTOR is meant to be used just for IPC.
   InputStreamLengthWrapper();
 
  private:
   ~InputStreamLengthWrapper();
 
+  template <typename M>
+  void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart, M* aManager);
+
   void SetSourceStream(already_AddRefed<nsIInputStream> aInputStream);
 
   nsCOMPtr<nsIInputStream> mInputStream;
 
   // Raw pointers because these are just QI of mInputStream.
   nsICloneableInputStream* mWeakCloneableInputStream;
   nsIIPCSerializableInputStream* mWeakIPCSerializableInputStream;
   nsISeekableStream* mWeakSeekableInputStream;
--- a/xpcom/io/NonBlockingAsyncInputStream.cpp
+++ b/xpcom/io/NonBlockingAsyncInputStream.cpp
@@ -313,34 +313,58 @@ NonBlockingAsyncInputStream::AsyncWait(n
 
   return runnable->Run();
 }
 
 // nsIIPCSerializableInputStream
 
 void NonBlockingAsyncInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
-    FileDescriptorArray& aFileDescriptors) {
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void NonBlockingAsyncInputStream::Serialize(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::ipc::PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void NonBlockingAsyncInputStream::Serialize(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void NonBlockingAsyncInputStream::Serialize(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    mozilla::ipc::PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+template <typename M>
+void NonBlockingAsyncInputStream::SerializeInternal(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart, M* aManager) {
   MOZ_ASSERT(mWeakIPCSerializableInputStream);
-  InputStreamHelper::SerializeInputStream(mInputStream, aParams,
-                                          aFileDescriptors);
+  InputStreamHelper::SerializeInputStream(
+      mInputStream, aParams, aFileDescriptors, aDelayedStart, aManager);
 }
 
 bool NonBlockingAsyncInputStream::Deserialize(
     const mozilla::ipc::InputStreamParams& aParams,
     const FileDescriptorArray& aFileDescriptors) {
   MOZ_CRASH("NonBlockingAsyncInputStream cannot be deserialized!");
   return true;
 }
 
-Maybe<uint64_t> NonBlockingAsyncInputStream::ExpectedSerializedLength() {
-  NS_ENSURE_TRUE(mWeakIPCSerializableInputStream, Nothing());
-  return mWeakIPCSerializableInputStream->ExpectedSerializedLength();
-}
-
 // nsISeekableStream
 
 NS_IMETHODIMP
 NonBlockingAsyncInputStream::Seek(int32_t aWhence, int64_t aOffset) {
   NS_ENSURE_STATE(mWeakSeekableInputStream);
   return mWeakSeekableInputStream->Seek(aWhence, aOffset);
 }
 
--- a/xpcom/io/NonBlockingAsyncInputStream.h
+++ b/xpcom/io/NonBlockingAsyncInputStream.h
@@ -39,16 +39,21 @@ class NonBlockingAsyncInputStream final 
   static nsresult Create(already_AddRefed<nsIInputStream> aInputStream,
                          nsIAsyncInputStream** aAsyncInputStream);
 
  private:
   explicit NonBlockingAsyncInputStream(
       already_AddRefed<nsIInputStream> aInputStream);
   ~NonBlockingAsyncInputStream();
 
+  template <typename M>
+  void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart, M* aManager);
+
   class AsyncWaitRunnable;
 
   void RunAsyncWaitCallback(AsyncWaitRunnable* aRunnable,
                             already_AddRefed<nsIInputStreamCallback> aCallback);
 
   nsCOMPtr<nsIInputStream> mInputStream;
 
   // Raw pointers because these are just QI of mInputStream.
--- a/xpcom/io/SlicedInputStream.cpp
+++ b/xpcom/io/SlicedInputStream.cpp
@@ -416,23 +416,53 @@ SlicedInputStream::OnInputStreamReady(ns
 
   return mWeakAsyncInputStream->AsyncWait(
       this, asyncWaitFlags, asyncWaitRequestedCount, asyncWaitEventTarget);
 }
 
 // nsIIPCSerializableInputStream
 
 void SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
-                                  FileDescriptorArray& aFileDescriptors) {
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  mozilla::ipc::PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
+                                  FileDescriptorArray& aFileDescriptors,
+                                  bool aDelayedStart,
+                                  mozilla::ipc::PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+template <typename M>
+void SlicedInputStream::SerializeInternal(
+    mozilla::ipc::InputStreamParams& aParams,
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart, M* aManager) {
   MOZ_ASSERT(mInputStream);
   MOZ_ASSERT(mWeakIPCSerializableInputStream);
 
   SlicedInputStreamParams params;
-  InputStreamHelper::SerializeInputStream(mInputStream, params.stream(),
-                                          aFileDescriptors);
+  InputStreamHelper::SerializeInputStream(
+      mInputStream, params.stream(), aFileDescriptors, aDelayedStart, aManager);
   params.start() = mStart;
   params.length() = mLength;
   params.curPos() = mCurPos;
   params.closed() = mClosed;
 
   aParams = params;
 }
 
@@ -461,24 +491,16 @@ bool SlicedInputStream::Deserialize(
   mStart = params.start();
   mLength = params.length();
   mCurPos = params.curPos();
   mClosed = params.closed();
 
   return true;
 }
 
-mozilla::Maybe<uint64_t> SlicedInputStream::ExpectedSerializedLength() {
-  if (!mInputStream || !mWeakIPCSerializableInputStream) {
-    return mozilla::Nothing();
-  }
-
-  return mWeakIPCSerializableInputStream->ExpectedSerializedLength();
-}
-
 // nsISeekableStream
 
 NS_IMETHODIMP
 SlicedInputStream::Seek(int32_t aWhence, int64_t aOffset) {
   NS_ENSURE_STATE(mInputStream);
   NS_ENSURE_STATE(mWeakSeekableInputStream);
 
   int64_t offset;
--- a/xpcom/io/SlicedInputStream.h
+++ b/xpcom/io/SlicedInputStream.h
@@ -56,16 +56,21 @@ class SlicedInputStream final : public n
                     uint64_t aStart, uint64_t aLength);
 
   // This CTOR is meant to be used just for IPC.
   SlicedInputStream();
 
  private:
   ~SlicedInputStream();
 
+  template <typename M>
+  void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart, M* aManager);
+
   void SetSourceStream(already_AddRefed<nsIInputStream> aInputStream);
 
   uint64_t AdjustRange(uint64_t aRange);
 
   nsCOMPtr<nsIInputStream> mInputStream;
 
   // Raw pointers because these are just QI of mInputStream.
   nsICloneableInputStream* mWeakCloneableInputStream;
--- a/xpcom/io/nsMultiplexInputStream.cpp
+++ b/xpcom/io/nsMultiplexInputStream.cpp
@@ -104,16 +104,21 @@ class nsMultiplexInputStream final : pub
   struct MOZ_STACK_CLASS ReadSegmentsState {
     nsCOMPtr<nsIInputStream> mThisStream;
     uint32_t mOffset;
     nsWriteSegmentFun mWriter;
     void* mClosure;
     bool mDone;
   };
 
+  template <typename M>
+  void SerializeInternal(InputStreamParams& aParams,
+                         FileDescriptorArray& aFileDescriptors,
+                         bool aDelayedStart, M* aManager);
+
   static nsresult ReadSegCb(nsIInputStream* aIn, void* aClosure,
                             const char* aFromRawSegment, uint32_t aToOffset,
                             uint32_t aCount, uint32_t* aWriteCount);
 
   bool IsSeekable() const;
   bool IsTellable() const;
   bool IsIPCSerializable() const;
   bool IsCloneable() const;
@@ -978,32 +983,61 @@ nsresult nsMultiplexInputStreamConstruct
     return NS_ERROR_NO_AGGREGATION;
   }
 
   RefPtr<nsMultiplexInputStream> inst = new nsMultiplexInputStream();
 
   return inst->QueryInterface(aIID, aResult);
 }
 
+void nsMultiplexInputStream::Serialize(
+    InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
+    bool aDelayedStart, mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
 void nsMultiplexInputStream::Serialize(InputStreamParams& aParams,
-                                       FileDescriptorArray& aFileDescriptors) {
+                                       FileDescriptorArray& aFileDescriptors,
+                                       bool aDelayedStart,
+                                       PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void nsMultiplexInputStream::Serialize(
+    InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
+    bool aDelayedStart, mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+void nsMultiplexInputStream::Serialize(InputStreamParams& aParams,
+                                       FileDescriptorArray& aFileDescriptors,
+                                       bool aDelayedStart,
+                                       PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+}
+
+template <typename M>
+void nsMultiplexInputStream::SerializeInternal(
+    InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
+    bool aDelayedStart, M* aManager) {
   MutexAutoLock lock(mLock);
 
   MultiplexInputStreamParams params;
 
   uint32_t streamCount = mStreams.Length();
 
   if (streamCount) {
     InfallibleTArray<InputStreamParams>& streams = params.streams();
 
     streams.SetCapacity(streamCount);
     for (uint32_t index = 0; index < streamCount; index++) {
       InputStreamParams childStreamParams;
       InputStreamHelper::SerializeInputStream(
-          mStreams[index].mStream, childStreamParams, aFileDescriptors);
+          mStreams[index].mStream, childStreamParams, aFileDescriptors,
+          aDelayedStart, aManager);
 
       streams.AppendElement(childStreamParams);
     }
   }
 
   params.currentStream() = mCurrentStream;
   params.status() = mStatus;
   params.startedReadingCurrent() = mStartedReadingCurrent;
@@ -1041,38 +1075,16 @@ bool nsMultiplexInputStream::Deserialize
 
   mCurrentStream = params.currentStream();
   mStatus = params.status();
   mStartedReadingCurrent = params.startedReadingCurrent();
 
   return true;
 }
 
-Maybe<uint64_t> nsMultiplexInputStream::ExpectedSerializedLength() {
-  MutexAutoLock lock(mLock);
-
-  bool lengthValueExists = false;
-  uint64_t expectedLength = 0;
-  uint32_t streamCount = mStreams.Length();
-  for (uint32_t index = 0; index < streamCount; index++) {
-    nsCOMPtr<nsIIPCSerializableInputStream> stream =
-        do_QueryInterface(mStreams[index].mStream);
-    if (!stream) {
-      continue;
-    }
-    Maybe<uint64_t> length = stream->ExpectedSerializedLength();
-    if (length.isNothing()) {
-      continue;
-    }
-    lengthValueExists = true;
-    expectedLength += length.value();
-  }
-  return lengthValueExists ? Some(expectedLength) : Nothing();
-}
-
 NS_IMETHODIMP
 nsMultiplexInputStream::GetCloneable(bool* aCloneable) {
   MutexAutoLock lock(mLock);
   // XXXnsm Cloning a multiplex stream which has started reading is not
   // permitted right now.
   if (mCurrentStream > 0 || mStartedReadingCurrent) {
     *aCloneable = false;
     return NS_OK;
--- a/xpcom/io/nsStorageStream.cpp
+++ b/xpcom/io/nsStorageStream.cpp
@@ -360,16 +360,20 @@ class nsStorageInputStream final : publi
   nsresult mStatus;
 
   uint32_t SegNum(uint32_t aPosition) {
     return aPosition >> mStorageStream->mSegmentSizeLog2;
   }
   uint32_t SegOffset(uint32_t aPosition) {
     return aPosition & (mSegmentSize - 1);
   }
+
+  template <typename M>
+  void SerializeInternal(InputStreamParams& aParams, bool aDelayedStart,
+                         M* aManager);
 };
 
 NS_IMPL_ISUPPORTS(nsStorageInputStream, nsIInputStream, nsISeekableStream,
                   nsITellableStream, nsIIPCSerializableInputStream,
                   nsICloneableInputStream)
 
 NS_IMETHODIMP
 nsStorageStream::NewInputStream(int32_t aStartingOffset,
@@ -542,24 +546,58 @@ nsresult nsStorageInputStream::Seek(uint
   mReadCursor = SegOffset(aPosition);
   uint32_t available = length - aPosition;
   mSegmentEnd = mReadCursor + XPCOM_MIN(mSegmentSize - mReadCursor, available);
   mLogicalCursor = aPosition;
   return NS_OK;
 }
 
 void nsStorageInputStream::Serialize(InputStreamParams& aParams,
-                                     FileDescriptorArray&) {
+                                     FileDescriptorArray&, bool aDelayedStart,
+                                     mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aDelayedStart, aManager);
+}
+
+void nsStorageInputStream::Serialize(InputStreamParams& aParams,
+                                     FileDescriptorArray&, bool aDelayedStart,
+                                     mozilla::ipc::PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aDelayedStart, aManager);
+}
+
+void nsStorageInputStream::Serialize(InputStreamParams& aParams,
+                                     FileDescriptorArray&, bool aDelayedStart,
+                                     mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aDelayedStart, aManager);
+}
+
+void nsStorageInputStream::Serialize(
+    InputStreamParams& aParams, FileDescriptorArray&, bool aDelayedStart,
+    mozilla::ipc::PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aDelayedStart, aManager);
+}
+
+template <typename M>
+void nsStorageInputStream::SerializeInternal(InputStreamParams& aParams,
+                                             bool aDelayedStart, M* aManager) {
+  uint64_t remaining = 0;
+  nsresult rv = Available(&remaining);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+  // If the string is known to be larger than 1MB, prefer sending it in chunks.
+  const uint64_t kTooLargeStream = 1024 * 1024;
+
+  if (remaining > kTooLargeStream) {
+    InputStreamHelper::SerializeInputStreamAsPipe(this, aParams, aDelayedStart,
+                                                  aManager);
+    return;
+  }
+
   nsCString combined;
   int64_t offset;
-  nsresult rv = Tell(&offset);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
-
-  uint64_t remaining;
-  rv = Available(&remaining);
+  rv = Tell(&offset);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   auto handle = combined.BulkWrite(remaining, 0, false, rv);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   uint32_t numRead = 0;
 
   rv = Read(handle.Elements(), remaining, &numRead);
@@ -571,23 +609,16 @@ void nsStorageInputStream::Serialize(Inp
   rv = Seek(NS_SEEK_SET, offset);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   StringInputStreamParams params;
   params.data() = combined;
   aParams = params;
 }
 
-Maybe<uint64_t> nsStorageInputStream::ExpectedSerializedLength() {
-  uint64_t remaining = 0;
-  DebugOnly<nsresult> rv = Available(&remaining);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
-  return Some(remaining);
-}
-
 bool nsStorageInputStream::Deserialize(const InputStreamParams& aParams,
                                        const FileDescriptorArray&) {
   MOZ_ASSERT_UNREACHABLE(
       "We should never attempt to deserialize a storage "
       "input stream.");
   return false;
 }
 
--- a/xpcom/io/nsStringStream.cpp
+++ b/xpcom/io/nsStringStream.cpp
@@ -50,16 +50,20 @@ class nsStringInputStream final : public
 
   nsStringInputStream() : mOffset(0) { Clear(); }
 
   nsresult Init(nsCString&& aString);
 
  private:
   ~nsStringInputStream() {}
 
+  template <typename M>
+  void SerializeInternal(InputStreamParams& aParams, bool aDelayedStart,
+                         M* aManager);
+
   uint32_t Length() const { return mData.Length(); }
 
   uint32_t LengthRemaining() const { return Length() - mOffset; }
 
   void Clear() { mData.SetIsVoid(true); }
 
   bool Closed() { return mData.IsVoid(); }
 
@@ -307,17 +311,55 @@ nsStringInputStream::Tell(int64_t* aOutW
   return NS_OK;
 }
 
 /////////
 // nsIIPCSerializableInputStream implementation
 /////////
 
 void nsStringInputStream::Serialize(InputStreamParams& aParams,
-                                    FileDescriptorArray& /* aFDs */) {
+                                    FileDescriptorArray& /* aFDs */,
+                                    bool aDelayedStart,
+                                    mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aDelayedStart, aManager);
+}
+
+void nsStringInputStream::Serialize(InputStreamParams& aParams,
+                                    FileDescriptorArray& /* aFDs */,
+                                    bool aDelayedStart,
+                                    PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aDelayedStart, aManager);
+}
+
+void nsStringInputStream::Serialize(InputStreamParams& aParams,
+                                    FileDescriptorArray& /* aFDs */,
+                                    bool aDelayedStart,
+                                    mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aDelayedStart, aManager);
+}
+
+void nsStringInputStream::Serialize(InputStreamParams& aParams,
+                                    FileDescriptorArray& /* aFDs */,
+                                    bool aDelayedStart,
+                                    PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aDelayedStart, aManager);
+}
+
+template <typename M>
+void nsStringInputStream::SerializeInternal(InputStreamParams& aParams,
+                                            bool aDelayedStart, M* aManager) {
+  // If the string is known to be larger than 1MB, prefer sending it in chunks.
+  const uint64_t kTooLargeStream = 1024 * 1024;
+
+  if (Length() > kTooLargeStream) {
+    InputStreamHelper::SerializeInputStreamAsPipe(this, aParams, aDelayedStart,
+                                                  aManager);
+    return;
+  }
+
   StringInputStreamParams params;
   params.data() = PromiseFlatCString(mData);
   aParams = params;
 }
 
 bool nsStringInputStream::Deserialize(const InputStreamParams& aParams,
                                       const FileDescriptorArray& /* aFDs */) {
   if (aParams.type() != InputStreamParams::TStringInputStreamParams) {
@@ -330,20 +372,16 @@ bool nsStringInputStream::Deserialize(co
   if (NS_FAILED(SetData(params.data()))) {
     NS_WARNING("SetData failed!");
     return false;
   }
 
   return true;
 }
 
-Maybe<uint64_t> nsStringInputStream::ExpectedSerializedLength() {
-  return Some(static_cast<uint64_t>(Length()));
-}
-
 /////////
 // nsICloneableInputStream implementation
 /////////
 
 NS_IMETHODIMP
 nsStringInputStream::GetCloneable(bool* aCloneableOut) {
   *aCloneableOut = true;
   return NS_OK;
--- a/xpcom/tests/gtest/TestNonBlockingAsyncInputStream.cpp
+++ b/xpcom/tests/gtest/TestNonBlockingAsyncInputStream.cpp
@@ -263,25 +263,28 @@ class QIInputStream final : public nsIIn
 
   // nsICloneableInputStream
   NS_IMETHOD GetCloneable(bool*) override { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD Clone(nsIInputStream**) override {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // nsIIPCSerializableInputStream
-  void Serialize(mozilla::ipc::InputStreamParams&,
-                 FileDescriptorArray&) override {}
+  void Serialize(mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool,
+                 mozilla::dom::nsIContentChild*) override {}
+  void Serialize(mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool,
+                 mozilla::ipc::PBackgroundChild*) override {}
+  void Serialize(mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool,
+                 mozilla::dom::nsIContentParent*) override {}
+  void Serialize(mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool,
+                 mozilla::ipc::PBackgroundParent*) override {}
   bool Deserialize(const mozilla::ipc::InputStreamParams&,
                    const FileDescriptorArray&) override {
     return false;
   }
-  mozilla::Maybe<uint64_t> ExpectedSerializedLength() override {
-    return mozilla::Nothing();
-  }
 
   // nsISeekableStream
   NS_IMETHOD Seek(int32_t, int64_t) override {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   NS_IMETHOD SetEOF() override { return NS_ERROR_NOT_IMPLEMENTED; }
 
   // nsITellableStream