Merge mozilla-inbound to mozilla-central a=merge
authorRazvan Maries <rmaries@mozilla.com>
Fri, 15 Mar 2019 05:40:21 +0200
changeset 522012 c525a24dffc34f710b52dfcb949fcafeb3f6bac6
parent 521983 5ce27c44f79e369501db52170709194a30d12f8a (diff)
parent 522011 f3500b0a2f3bbce27476b4602d1e7be26524d909 (current diff)
child 522013 6149ddaa39a6436f6d212da737be23bfa1bbf914
child 522064 759a68d0af0fbdf24b36101503d8c61a879cfc25
push id10870
push usernbeleuzu@mozilla.com
push dateFri, 15 Mar 2019 20:00:07 +0000
treeherdermozilla-beta@c594aee5b7a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central a=merge
devtools/client/debugger/new/src/actions/sources/loadSourceText.js
devtools/client/debugger/new/src/actions/types/SourceAction.js
devtools/client/debugger/new/src/reducers/sources.js
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -236,16 +236,17 @@ tasks:
                   cd /builds/worker/checkouts/gecko &&
                   ln -s /builds/worker/artifacts artifacts &&
                   ./mach --log-no-times taskgraph decision
                   --pushlog-id='${push.pushlog_id}'
                   --pushdate='${push.pushdate}'
                   --project='${repository.project}'
                   --owner='${ownerEmail}'
                   --level='${repository.level}'
+                  --tasks-for='${tasks_for}'
                   --base-repository="$GECKO_BASE_REPOSITORY"
                   --head-repository="$GECKO_HEAD_REPOSITORY"
                   --head-ref="$GECKO_HEAD_REF"
                   --head-rev="$GECKO_HEAD_REV"
                   ${extraArgs}
 
           artifacts:
             'public':
--- a/browser/actors/NetErrorChild.jsm
+++ b/browser/actors/NetErrorChild.jsm
@@ -179,16 +179,20 @@ class NetErrorChild extends ActorChild {
       }
     }
 
     technicalInfo.appendChild(doc.createTextNode(msg1));
 
     if (input.data.isDomainMismatch) {
       let subjectAltNames = input.data.certSubjectAltNames.split(",");
       let numSubjectAltNames = subjectAltNames.length;
+
+      subjectAltNames = subjectAltNames.filter(name => name.length > 0);
+      numSubjectAltNames = subjectAltNames.length;
+
       let msgPrefix = "";
       if (numSubjectAltNames != 0) {
         if (numSubjectAltNames == 1) {
           if (newErrorPagesEnabled) {
             technicalInfo.textContent = "";
             let brandName = gBrandBundle.GetStringFromName("brandShortName");
             msgPrefix = gPipNSSBundle.formatStringFromName("certErrorMismatchSinglePrefix3", [brandName, hostString], 2) + " ";
             msgPrefix += gPipNSSBundle.GetStringFromName("certErrorMismatchSinglePrefix");
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -713,20 +713,22 @@ html|input.urlbar-input {
 #urlbar:not([actiontype="switchtab"]):not([actiontype="extension"]) > #urlbar-display-box,
 #urlbar:not([actiontype="switchtab"]) > #urlbar-display-box > #switchtab,
 #urlbar:not([actiontype="extension"]) > #urlbar-display-box > #extension {
   display: none;
 }
 
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="loginsFooter"] {
   color: var(--btn-text-color);
-  padding: 0 20px;
   min-height: 40px;
   border-top: 1px solid rgba(38,38,38,.15);
   background-color: #EDEDED;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 }
 
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="loginsFooter"]:hover,
 #PopupAutoComplete > richlistbox > richlistitem[originaltype="loginsFooter"][selected] {
   background-color: #DCDCDE;
 }
 
 #PopupAutoComplete[firstresultstyle="insecureWarning"] {
--- a/browser/base/content/test/about/browser.ini
+++ b/browser/base/content/test/about/browser.ini
@@ -8,16 +8,17 @@ support-files =
   dummy_page.html
 prefs =
   browser.newtabpage.activity-stream.improvesearch.handoffToAwesomebar=false
 
 [browser_aboutCertError.js]
 [browser_aboutCertError_clockSkew.js]
 [browser_aboutCertError_exception.js]
 [browser_aboutCertError_mitm.js]
+[browser_aboutCertError_noSubjectAltName.js]
 [browser_aboutCertError_telemetry.js]
 [browser_aboutHome_search_POST.js]
 [browser_aboutHome_search_composing.js]
 [browser_aboutHome_search_searchbar.js]
 [browser_aboutHome_search_suggestion.js]
 skip-if = os == "mac" || (os == "linux" && (!debug || bits == 64)) || (os == 'win' && os_version == '10.0' && bits == 64 && !debug) # Bug 1399648, bug 1402502
 [browser_aboutHome_search_telemetry.js]
 [browser_aboutNetError.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/about/browser_aboutCertError_noSubjectAltName.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const UNKNOWN_ISSUER = "https://no-subject-alt-name.example.com:443";
+
+const checkAdvancedAndGetTechnicalInfoText = async () => {
+  let doc = content.document;
+
+  let advancedButton = doc.getElementById("advancedButton");
+  ok(advancedButton, "advancedButton found");
+  is(advancedButton.hasAttribute("disabled"), false, "advancedButton should be clickable");
+  advancedButton.click();
+
+  let badCertAdvancedPanel = doc.getElementById("badCertAdvancedPanel");
+  ok(badCertAdvancedPanel, "badCertAdvancedPanel found");
+
+  let badCertTechnicalInfo = doc.getElementById("badCertTechnicalInfo");
+  ok(badCertTechnicalInfo, "badCertTechnicalInfo found");
+
+  let errorCode = doc.getElementById("errorCode").innerHTML;
+  is(errorCode, "SSL_ERROR_BAD_CERT_DOMAIN");
+
+  let viewCertificate = doc.getElementById("viewCertificate");
+  ok(viewCertificate, "viewCertificate found");
+
+  return badCertTechnicalInfo.innerHTML;
+};
+
+const checkCorrectMessages = (message) => {
+  let isCorrectMessage =
+    message.includes("Websites prove their identity via certificates."
+      + " Nightly does not trust this site because it uses a certificate that is"
+      + " not valid for no-subject-alt-name.example.com");
+  is(isCorrectMessage, true, "That message should appear");
+  let isWrongMessage =
+    message.includes("The certificate is only valid for ");
+  is(isWrongMessage, false, "That message shouldn't appear");
+};
+
+add_task(async function checkUntrustedCertError() {
+  info(`Loading ${UNKNOWN_ISSUER} which does not have a subject specified in the certificate`);
+  let tab = await openErrorPage(UNKNOWN_ISSUER);
+  let browser = tab.linkedBrowser;
+  info("Clicking the exceptionDialogButton in advanced panel");
+  let badCertTechnicalInfoText =
+    await ContentTask.spawn(browser, null, checkAdvancedAndGetTechnicalInfoText);
+  checkCorrectMessages(badCertTechnicalInfoText, browser);
+  BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
--- a/browser/themes/shared/aboutNetError-new.css
+++ b/browser/themes/shared/aboutNetError-new.css
@@ -189,16 +189,18 @@ body:not(:-moz-any(.clockSkewError,.badS
   padding: 1em 17.5%;
   box-sizing: border-box;
 }
 
 #certificateErrorText {
   font-family: monospace;
   white-space: pre-wrap;
   padding: 1em 0;
+  display: flex;
+  flex-wrap: wrap;
 }
 
 #cert_domain_link:not([href]) {
   color: var(--in-content-page-color);
   text-decoration: none;
 }
 
 .exceptionDialogButtonContainer {
--- a/browser/themes/shared/aboutNetError.css
+++ b/browser/themes/shared/aboutNetError.css
@@ -154,16 +154,18 @@ span#hostname {
   padding: 1em 17.5%;
   box-sizing: border-box;
 }
 
 #certificateErrorText {
   font-family: monospace;
   white-space: pre-wrap;
   padding: 1em 0;
+  display: flex;
+  flex-wrap: wrap;
 }
 
 #cert_domain_link:not([href]) {
   color: var(--in-content-page-color);
   text-decoration: none;
 }
 
 .exceptionDialogButtonContainer {
--- a/browser/themes/shared/browser.inc.css
+++ b/browser/themes/shared/browser.inc.css
@@ -211,16 +211,20 @@
   list-style-image: url(resource://activity-stream/data/content/assets/glyph-help-24.svg);
 }
 
 #cfr-notification-header-image:hover {
   background-color: hsla(0,0%,70%,.2);
   border-radius: 2px;
 }
 
+#contextual-feature-recommendation-notification {
+  width: 343px;
+}
+
 #contextual-feature-recommendation-notification .popup-notification-icon {
   margin-inline-end: 4px;
 }
 
 #contextual-feature-recommendation-notification .popup-notification-body-container {
   padding-bottom: 0;
 }
 
deleted file mode 100644
--- a/build/build-clang/clang-tidy-win32.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "llvm_revision": "349247",
-    "stages": "1",
-    "build_libcxx": false,
-    "build_type": "Release",
-    "assertions": false,
-    "build_clang_tidy": true,
-    "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_701/final",
-    "clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_701/final",
-    "extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/tags/RELEASE_701/final",
-    "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_701/final",
-    "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_701/final",
-    "python_path": "c:/mozilla-build/python/python.exe",
-    "cc": "cl.exe",
-    "cxx": "cl.exe",
-    "patches": [
-    ]
-}
index 46f4626143abb7d3f0d4d5d2cfad72cfee067c20..fe1d307533a9a85b905ff3d49acee61e65122d7d
GIT binary patch
literal 229376
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
z00000000000000000000000000000000000000000000000000000000000000000
z000000O0=u8G<@~2`<V;{MTCix10E{l_tR+&*f2g3~Dfg#bU4$`cP<=;!F#5f;FC=
z!C>*|oD@2ZLE+KO#aU)*1S>p+iDt0SsT?+&XDZGiDiHMX;-9)V5l=J5=8j8Ga3MK+
zARbgYhi4?tF~pY7Vuz*2CDExoA0}@QC53Jv&eWG9Xya28*i?$1c#5tvfrw9MC9~L>
ztQaaqM?6_ui{OaoCQ_VS$uV>m4ZZOgylgFTuBH;f7%jx(q;q+6nud6)IyM!poJ;3q
z&^c=2sjAup1W(ImQBuBkNIy24rXtQ(#un5*8|^P8ajqh^c3e6$p36vJ(P;|e$@18e
zQrOf)29M6=$%&`RY7lI(btZkY#xmkOX&r)7+Zt0?G;x1QiSs4(2xL4XC56F4%Q3TK
zXbi4+UV?ZI2~~oX9Gy$0q|zxo9)+4rl1Fz2oBTYS;FjQ^pjuEYNEQqfbQh@cU-29H
zTlus3x%_B;Z@wv?kbft?PT<0q&9Bd2Be*X(Dp(~b7o-Y81={>~{7d|u{000`{5ZZJ
z-zq;Z|6%_0uHMA~00000000000000000000000000000000000000000000000000
z000000000000000000000000000000000000000000000|Ci_zT=03hJ9~|uVflP#
zwZNfo;*CVtmFw(mu#BmJ3r^`ODK4L$e4$!-?Tp(!L!{1FV;SUxg}e6OCwzKSpof22
zUSfHrKq<DHBmsxF>MYk1%eCmNQgbZVth2JFST3=%H8sI<jXTRV!g38e%Qe7q^*hVe
z!*X>y%hkbhwL8nz!g4h`%hkYg)jP{o!*W$S%T>X0l{@PzB`jC5v$6_Uu6$>?a#*fx
dXSp(1u5@R)Qdq8JXSoC{S3-y2BG*yw{{ynUeRu!>
index 6f96def91f9228b86ca8f1e8b98f798852d3b1a3..c40fb77c5bfb3176f51dac2cbcd68045f4d1da49
GIT binary patch
literal 294912
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
zBuawev#YE*+BE88w4^7B{l}{K^z6&b>v?Yn-0mGsu_#VejwHt<*OuohUk;4#^*mka
z@r|kT)bsNPsWP&jJ^X^y_&V<(qhm##(eaIbpHpz=z-;;s#SWJP)IaLTj^8;x>drgc
zK=iKQs9|8?gF))%xy6-pck?|w9!;_l-`G0v_@Ca{iHInB{<}vF00000`2PW#%`ejU
zw?y$P@pGHs0000000000000000000000000000000000000000000000000000000
z0000000000000000000000000000000000000000004mhhf$G|5lgDNbC7P0Abr+I
zC`rkvB_)Y@Xf~&k#?KSQ|A=4S{00C300000000000000000000000000000000000
z000000000000000000000000000000000000000000000000000000000000{0~7!
zN<>Whb3j5$N<>W)-$_Ior%M!fCr&qR;{S9u000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z0QkRL5E<5;80jr1h7_S7-A_i!!e@>43k(QG1xNC0qk}^+9vC-ND4Jg@EYvF?7!w*P
z$AM(~IVTMZgGoRX#@83cZ;cKK#rS*52_X?br_i!+nFj}WV0_X1dSMuMv^&39U?|29
z6NL)J1o)Fmk~&Z$MgEwXbQ_nJZzww0|L22P2Zx1(ZqEN74~BIoJ8Vdd#6Fj!MN<Eq
zoq~mAzttZ%s8~p}wdB~4+kf7mWT7(&2=fm`Vf^_IV9*hAf=Gd1Id}Y#Q<`7*0KYrh
zHO!MgbTcyl=E6Kku3wS2TcO>;em*3>uD>V7AB_(F`4cH46@OJldUMHt{h0h>n~(A{
zXhcA8s8^);=4xd9QGRH3bhz}-)k?de<fM=i6x0&Q`pL_5#MH!WJZ@g7U|&=y%3m||
z*Ggp2hfscjzGxY@06&t=&7kt%*mN}UGeo5E9YpaR@gwm||6e~b000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z000000000000000004mhed1?`SQ$x0s8PP5=wN@;<{%&-l$lhF7#)uB-@N6AcE@bq
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
new file mode 100644
--- /dev/null
+++ b/build/pgo/certs/noSubjectAltName.certspec
@@ -0,0 +1,2 @@
+issuer:printableString/CN=Temporary Certificate Authority/O=Mozilla Testing/OU=Profile Guided Optimization
+subject:certificate without subjectAlternativeNames
--- a/build/pgo/server-locations.txt
+++ b/build/pgo/server-locations.txt
@@ -114,16 +114,17 @@ https://self-signed.example.com:443    p
 https://untrusted.example.com:443      privileged,cert=untrusted
 https://expired.example.com:443        privileged,cert=expired
 https://requestclientcert.example.com:443         privileged,clientauth=request
 https://requireclientcert.example.com:443         privileged,clientauth=require
 https://mismatch.expired.example.com:443	privileged,cert=expired
 https://mismatch.untrusted.example.com:443	privileged,cert=untrusted
 https://untrusted-expired.example.com:443	privileged,cert=untrustedandexpired
 https://mismatch.untrusted-expired.example.com:443	privileged,cert=untrustedandexpired
+https://no-subject-alt-name.example.com:443   cert=noSubjectAltName
 
 # Prevent safebrowsing tests from hitting the network for its-a-trap.html and
 # its-an-attack.html.
 http://www.itisatrap.org:80
 https://www.itisatrap.org:443
 
 #
 # These are subdomains of <ält.example.org>.
--- a/devtools/client/debugger/new/dist/debugger.css
+++ b/devtools/client/debugger/new/dist/debugger.css
@@ -3174,17 +3174,18 @@ html .breakpoints-list .breakpoint.pause
 
 .breakpoints-list .breakpoint .breakpoint-line {
   font-size: 11px;
   color: var(--theme-comment);
   min-width: 16px;
   text-align: end;
 }
 
-.breakpoints-list .breakpoint:hover .breakpoint-line {
+.breakpoints-list .breakpoint:hover .breakpoint-line,
+.breakpoints-list .breakpoint-line-close:focus-within .breakpoint-line {
   color: transparent;
 }
 
 .breakpoints-list .breakpoint.paused:hover {
   border-color: var(--breakpoint-active-color-hover);
 }
 
 .breakpoints-list .breakpoint-label {
@@ -4003,18 +4004,16 @@ html[dir="rtl"] .event-listeners-content
 	margin-inline-start: 0px;
 	margin-top: 0px;
 	margin-bottom: 0px;
 }
 /* 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/>. */
 
-
-
 .scopes-content .toggle-map-scopes {
   border-bottom: 1px solid var(--theme-splitter-color);
   margin-bottom: 3px;
   margin-left: 10px;
   padding: 0.5em 0;
 }
 
 .scopes-content .toggle-map-scopes input {
--- a/devtools/client/debugger/new/src/components/Editor/Tab.js
+++ b/devtools/client/debugger/new/src/components/Editor/Tab.js
@@ -18,16 +18,17 @@ import type { Source } from "../../types
 import actions from "../../actions";
 
 import {
   getDisplayPath,
   getFileURL,
   getRawSourceURL,
   getSourceQueryString,
   getTruncatedFileName,
+  isJavaScript,
   isPretty,
   shouldBlackbox
 } from "../../utils/source";
 import { copyToTheClipboard } from "../../utils/clipboard";
 import { getTabMenuItems } from "../../utils/tabs";
 
 import {
   getSelectedSource,
@@ -144,17 +145,17 @@ class Tab extends PureComponent<Props> {
           disabled: !shouldBlackbox(source),
           click: () => toggleBlackBox(source)
         }
       },
       {
         item: {
           ...tabMenuItems.prettyPrint,
           click: () => togglePrettyPrint(tab),
-          disabled: isPretty(sourceTab)
+          disabled: isPretty(source) || !isJavaScript(source)
         }
       }
     ];
 
     showMenu(e, buildMenu(items));
   }
 
   isProjectSearchEnabled() {
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoints.css
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoints.css
@@ -130,17 +130,18 @@ html .breakpoints-list .breakpoint.pause
 
 .breakpoints-list .breakpoint .breakpoint-line {
   font-size: 11px;
   color: var(--theme-comment);
   min-width: 16px;
   text-align: end;
 }
 
-.breakpoints-list .breakpoint:hover .breakpoint-line {
+.breakpoints-list .breakpoint:hover .breakpoint-line,
+.breakpoints-list .breakpoint-line-close:focus-within .breakpoint-line {
   color: transparent;
 }
 
 .breakpoints-list .breakpoint.paused:hover {
   border-color: var(--breakpoint-active-color-hover);
 }
 
 .breakpoints-list .breakpoint-label {
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -53,30 +53,16 @@ static StaticAutoPtr<BrowsingContextMap<
 
 static void Register(BrowsingContext* aBrowsingContext) {
   MOZ_ALWAYS_TRUE(
       sBrowsingContexts->putNew(aBrowsingContext->Id(), aBrowsingContext));
 
   aBrowsingContext->Group()->Register(aBrowsingContext);
 }
 
-static void Sync(BrowsingContext* aBrowsingContext) {
-  if (!XRE_IsContentProcess()) {
-    return;
-  }
-
-  auto cc = ContentChild::GetSingleton();
-  MOZ_DIAGNOSTIC_ASSERT(cc);
-  RefPtr<BrowsingContext> parent = aBrowsingContext->GetParent();
-  BrowsingContext* opener = aBrowsingContext->GetOpener();
-  cc->SendAttachBrowsingContext(parent, opener,
-                                BrowsingContextId(aBrowsingContext->Id()),
-                                aBrowsingContext->Name());
-}
-
 BrowsingContext* BrowsingContext::TopLevelBrowsingContext() {
   BrowsingContext* bc = this;
   while (bc->mParent) {
     bc = bc->mParent;
   }
   return bc;
 }
 
@@ -116,197 +102,205 @@ already_AddRefed<BrowsingContext> Browsi
   MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->mType == aType);
 
   uint64_t id = nsContentUtils::GenerateBrowsingContextId();
 
   MOZ_LOG(GetLog(), LogLevel::Debug,
           ("Creating 0x%08" PRIx64 " in %s", id,
            XRE_IsParentProcess() ? "Parent" : "Child"));
 
+  // Determine which BrowsingContextGroup this context should be created in.
+  RefPtr<BrowsingContextGroup> group =
+      BrowsingContextGroup::Select(aParent, aOpener);
+
   RefPtr<BrowsingContext> context;
   if (XRE_IsParentProcess()) {
-    context = new CanonicalBrowsingContext(aParent, aOpener, aName, id,
+    context = new CanonicalBrowsingContext(aParent, group, id,
                                            /* aProcessId */ 0, aType);
   } else {
-    context = new BrowsingContext(aParent, aOpener, aName, id, aType);
+    context = new BrowsingContext(aParent, group, id, aType);
+  }
+
+  // The name and opener fields need to be explicitly initialized. Don't bother
+  // using transactions to set them, as we haven't been attached yet.
+  context->mName = aName;
+  context->mOpenerId = aOpener ? aOpener->Id() : 0;
+
+  if (aParent) {
+    context->mCrossOriginPolicy = aParent->mCrossOriginPolicy;
+  } else if (aOpener) {
+    context->mCrossOriginPolicy = aOpener->mCrossOriginPolicy;
+  } else {
+    context->mCrossOriginPolicy = nsILoadInfo::CROSS_ORIGIN_POLICY_NULL;
   }
 
   Register(context);
 
   // Attach the browsing context to the tree.
   context->Attach();
 
   return context.forget();
 }
 
 /* static */
 already_AddRefed<BrowsingContext> BrowsingContext::CreateFromIPC(
-    BrowsingContext* aParent, BrowsingContext* aOpener, const nsAString& aName,
-    uint64_t aId, ContentParent* aOriginProcess) {
-  MOZ_DIAGNOSTIC_ASSERT(aOriginProcess || XRE_IsContentProcess(),
-                        "Parent Process IPC contexts need a Content Process.");
-  MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->IsContent());
+    BrowsingContext::IPCInitializer&& aInit, BrowsingContextGroup* aGroup,
+    ContentParent* aOriginProcess) {
+  MOZ_DIAGNOSTIC_ASSERT(aOriginProcess || XRE_IsContentProcess());
+  MOZ_DIAGNOSTIC_ASSERT(aGroup);
+
+  uint64_t originId = aOriginProcess ? aOriginProcess->ChildID() : 0;
 
   MOZ_LOG(GetLog(), LogLevel::Debug,
-          ("Creating 0x%08" PRIx64 " from IPC (origin=0x%08" PRIx64 ")", aId,
-           aOriginProcess ? uint64_t(aOriginProcess->ChildID()) : 0));
+          ("Creating 0x%08" PRIx64 " from IPC (origin=0x%08" PRIx64 ")",
+           aInit.mId, originId));
+
+  RefPtr<BrowsingContext> parent = aInit.GetParent();
 
   RefPtr<BrowsingContext> context;
   if (XRE_IsParentProcess()) {
-    context = new CanonicalBrowsingContext(
-        aParent, aOpener, aName, aId, aOriginProcess->ChildID(), Type::Content);
-
-    context->Group()->Subscribe(aOriginProcess);
+    context = new CanonicalBrowsingContext(parent, aGroup, aInit.mId, originId,
+                                           Type::Content);
   } else {
-    context = new BrowsingContext(aParent, aOpener, aName, aId, Type::Content);
+    context = new BrowsingContext(parent, aGroup, aInit.mId, Type::Content);
   }
 
   Register(context);
 
-  context->Attach();
+  // Initialize all of our fields from IPC. We don't have to worry about
+  // mOpenerId, as we won't try to dereference it immediately.
+#define MOZ_BC_FIELD(name, ...) context->m##name = aInit.m##name;
+#include "mozilla/dom/BrowsingContextFieldList.h"
+
+  // Caller handles attaching us to the tree.
 
   return context.forget();
 }
 
 BrowsingContext::BrowsingContext(BrowsingContext* aParent,
-                                 BrowsingContext* aOpener,
-                                 const nsAString& aName,
+                                 BrowsingContextGroup* aGroup,
                                  uint64_t aBrowsingContextId, Type aType)
-    : mName(aName),
-      mClosed(false),
-      mType(aType),
+    : mType(aType),
       mBrowsingContextId(aBrowsingContextId),
+      mGroup(aGroup),
       mParent(aParent),
-      mOpener(aOpener),
-      mIsActivatedByUserGesture(false) {
-  mCrossOriginPolicy = nsILoadInfo::CROSS_ORIGIN_POLICY_NULL;
-  // Specify our group in our constructor. We will explicitly join the group
-  // when we are registered, as doing so will take a reference.
-  if (mParent) {
-    mGroup = mParent->Group();
-    mCrossOriginPolicy = mParent->CrossOriginPolicy();
-  } else if (mOpener) {
-    mGroup = mOpener->Group();
-    mCrossOriginPolicy = mOpener->CrossOriginPolicy();
-  } else {
-    // To ensure the group has a unique ID, we will use our ID, as the founder
-    // of this BrowsingContextGroup.
-    mGroup = new BrowsingContextGroup();
-  }
+      mIsInProcess(false) {
+  MOZ_RELEASE_ASSERT(!mParent || mParent->Group() == mGroup);
+  MOZ_RELEASE_ASSERT(mBrowsingContextId != 0);
+  MOZ_RELEASE_ASSERT(mGroup);
 }
 
 void BrowsingContext::SetDocShell(nsIDocShell* aDocShell) {
   // XXX(nika): We should communicate that we are now an active BrowsingContext
   // process to the parent & do other validation here.
   MOZ_RELEASE_ASSERT(nsDocShell::Cast(aDocShell)->GetBrowsingContext() == this);
   mDocShell = aDocShell;
+  mIsInProcess = true;
 }
 
-void BrowsingContext::Attach() {
+void BrowsingContext::Attach(bool aFromIPC) {
   MOZ_LOG(GetLog(), LogLevel::Debug,
           ("%s: %s 0x%08" PRIx64 " to 0x%08" PRIx64,
            XRE_IsParentProcess() ? "Parent" : "Child",
            sCachedBrowsingContexts->has(Id()) ? "Re-connecting" : "Connecting",
            Id(), mParent ? mParent->Id() : 0));
 
   sCachedBrowsingContexts->remove(Id());
 
   auto* children = mParent ? &mParent->mChildren : &mGroup->Toplevels();
   MOZ_DIAGNOSTIC_ASSERT(!children->Contains(this));
 
   children->AppendElement(this);
 
-  Sync(this);
+  // Send attach to our parent if we need to.
+  if (!aFromIPC && XRE_IsContentProcess()) {
+    ContentChild::GetSingleton()->SendAttachBrowsingContext(
+        GetIPCInitializer());
+  }
 }
 
-void BrowsingContext::Detach() {
+void BrowsingContext::Detach(bool aFromIPC) {
   MOZ_LOG(GetLog(), LogLevel::Debug,
           ("%s: Detaching 0x%08" PRIx64 " from 0x%08" PRIx64,
            XRE_IsParentProcess() ? "Parent" : "Child", Id(),
            mParent ? mParent->Id() : 0));
 
   RefPtr<BrowsingContext> kungFuDeathGrip(this);
 
   BrowsingContextMap<RefPtr>::Ptr p;
   if (sCachedBrowsingContexts && (p = sCachedBrowsingContexts->lookup(Id()))) {
     MOZ_DIAGNOSTIC_ASSERT(!mParent || !mParent->mChildren.Contains(this));
     MOZ_DIAGNOSTIC_ASSERT(!mGroup || !mGroup->Toplevels().Contains(this));
     sCachedBrowsingContexts->remove(p);
   } else {
-    Children& children = mParent ? mParent->mChildren : mGroup->Toplevels();
+    Children* children = nullptr;
+    if (mParent) {
+      children = &mParent->mChildren;
+    } else if (mGroup) {
+      children = &mGroup->Toplevels();
+    }
 
-    // TODO(farre): This assert looks extremely fishy, I know, but
-    // what we're actually saying is this: if we're detaching, but our
-    // parent doesn't have any children, it is because we're being
-    // detached by the cycle collector destroying docshells out of
-    // order.
-    MOZ_DIAGNOSTIC_ASSERT(children.IsEmpty() || children.Contains(this));
+    if (children) {
+      // TODO(farre): This assert looks extremely fishy, I know, but
+      // what we're actually saying is this: if we're detaching, but our
+      // parent doesn't have any children, it is because we're being
+      // detached by the cycle collector destroying docshells out of
+      // order.
+      MOZ_DIAGNOSTIC_ASSERT(children->IsEmpty() || children->Contains(this));
 
-    children.RemoveElement(this);
+      children->RemoveElement(this);
+    }
   }
 
-  Group()->Unregister(this);
-
-  if (!XRE_IsContentProcess()) {
-    return;
+  if (mGroup) {
+    mGroup->Unregister(this);
   }
 
-  auto cc = ContentChild::GetSingleton();
-  MOZ_DIAGNOSTIC_ASSERT(cc);
-  cc->SendDetachBrowsingContext(this, false /* aMoveToBFCache */);
+  // As our nsDocShell is going away, this should implicitly mark us as closed.
+  // We directly set our member, rather than using a transaction as we're going
+  // to send a `Detach` message to other processes either way.
+  mClosed = true;
+
+  if (!aFromIPC && XRE_IsContentProcess()) {
+    auto cc = ContentChild::GetSingleton();
+    MOZ_DIAGNOSTIC_ASSERT(cc);
+    cc->SendDetachBrowsingContext(this, false /* aMoveToBFCache */);
+  }
 }
 
-void BrowsingContext::CacheChildren() {
+void BrowsingContext::CacheChildren(bool aFromIPC) {
   if (mChildren.IsEmpty()) {
     return;
   }
 
   MOZ_LOG(GetLog(), LogLevel::Debug,
           ("%s: Caching children of 0x%08" PRIx64 "",
            XRE_IsParentProcess() ? "Parent" : "Child", Id()));
 
   MOZ_ALWAYS_TRUE(sCachedBrowsingContexts->reserve(mChildren.Length()));
 
   for (BrowsingContext* child : mChildren) {
     MOZ_ALWAYS_TRUE(sCachedBrowsingContexts->putNew(child->Id(), child));
   }
   mChildren.Clear();
 
-  if (!XRE_IsContentProcess()) {
-    return;
+  if (!aFromIPC && XRE_IsContentProcess()) {
+    auto cc = ContentChild::GetSingleton();
+    MOZ_DIAGNOSTIC_ASSERT(cc);
+    cc->SendDetachBrowsingContext(this, true /* aMoveToBFCache */);
   }
-
-  auto cc = ContentChild::GetSingleton();
-  MOZ_DIAGNOSTIC_ASSERT(cc);
-  cc->SendDetachBrowsingContext(this, true /* aMoveToBFCache */);
 }
 
 bool BrowsingContext::IsCached() { return sCachedBrowsingContexts->has(Id()); }
 
 void BrowsingContext::GetChildren(
     nsTArray<RefPtr<BrowsingContext>>& aChildren) {
   MOZ_ALWAYS_TRUE(aChildren.AppendElements(mChildren));
 }
 
-void BrowsingContext::SetOpener(BrowsingContext* aOpener) {
-  if (mOpener == aOpener) {
-    return;
-  }
-
-  mOpener = aOpener;
-
-  if (!XRE_IsContentProcess()) {
-    return;
-  }
-
-  auto cc = ContentChild::GetSingleton();
-  MOZ_DIAGNOSTIC_ASSERT(cc);
-  cc->SendSetOpenerBrowsingContext(this, aOpener);
-}
-
 // FindWithName follows the rules for choosing a browsing context,
 // with the exception of sandboxing for iframes. The implementation
 // for arbitrarily choosing between two browsing contexts with the
 // same name is as follows:
 //
 // 1) The start browsing context, i.e. 'this'
 // 2) Descendants in insertion order
 // 3) The parent
@@ -478,60 +472,32 @@ JSObject* BrowsingContext::WrapObject(JS
 
 void BrowsingContext::NotifyUserGestureActivation() {
   // We would set the user gesture activation flag on the top level browsing
   // context, which would automatically be sync to other top level browsing
   // contexts which are in the different process.
   RefPtr<BrowsingContext> topLevelBC = TopLevelBrowsingContext();
   USER_ACTIVATION_LOG("Get top level browsing context 0x%08" PRIx64,
                       topLevelBC->Id());
-  topLevelBC->SetUserGestureActivation();
-
-  if (!XRE_IsContentProcess()) {
-    return;
-  }
-  auto cc = ContentChild::GetSingleton();
-  MOZ_ASSERT(cc);
-  cc->SendSetUserGestureActivation(topLevelBC, true);
+  topLevelBC->SetIsActivatedByUserGesture(true);
 }
 
 void BrowsingContext::NotifyResetUserGestureActivation() {
   // We would reset the user gesture activation flag on the top level browsing
   // context, which would automatically be sync to other top level browsing
   // contexts which are in the different process.
   RefPtr<BrowsingContext> topLevelBC = TopLevelBrowsingContext();
   USER_ACTIVATION_LOG("Get top level browsing context 0x%08" PRIx64,
                       topLevelBC->Id());
-  topLevelBC->ResetUserGestureActivation();
-
-  if (!XRE_IsContentProcess()) {
-    return;
-  }
-  auto cc = ContentChild::GetSingleton();
-  MOZ_ASSERT(cc);
-  cc->SendSetUserGestureActivation(topLevelBC, false);
-}
-
-void BrowsingContext::SetUserGestureActivation() {
-  MOZ_ASSERT(!mParent, "Set user activation flag on non top-level context!");
-  USER_ACTIVATION_LOG(
-      "Set user gesture activation for browsing context 0x%08" PRIx64, Id());
-  mIsActivatedByUserGesture = true;
+  topLevelBC->SetIsActivatedByUserGesture(false);
 }
 
 bool BrowsingContext::GetUserGestureActivation() {
   RefPtr<BrowsingContext> topLevelBC = TopLevelBrowsingContext();
-  return topLevelBC->mIsActivatedByUserGesture;
-}
-
-void BrowsingContext::ResetUserGestureActivation() {
-  MOZ_ASSERT(!mParent, "Clear user activation flag on non top-level context!");
-  USER_ACTIVATION_LOG(
-      "Reset user gesture activation for browsing context 0x%08" PRIx64, Id());
-  mIsActivatedByUserGesture = false;
+  return topLevelBC->GetIsActivatedByUserGesture();
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren, mParent, mGroup)
   if (XRE_IsParentProcess()) {
     CanonicalBrowsingContext::Cast(tmp)->Unlink();
@@ -589,40 +555,49 @@ void BrowsingContext::Location(JSContext
   }
 }
 
 void BrowsingContext::Close(CallerType aCallerType, ErrorResult& aError) {
   // FIXME We need to set mClosed, but only once we're sending the
   //       DOMWindowClose event (which happens in the process where the
   //       document for this browsing context is loaded).
   //       See https://bugzilla.mozilla.org/show_bug.cgi?id=1516343.
-  ContentChild* cc = ContentChild::GetSingleton();
-  cc->SendWindowClose(this, aCallerType == CallerType::System);
+  if (ContentChild* cc = ContentChild::GetSingleton()) {
+    cc->SendWindowClose(this, aCallerType == CallerType::System);
+  } else if (ContentParent* cp = Canonical()->GetContentParent()) {
+    Unused << cp->SendWindowClose(this, aCallerType == CallerType::System);
+  }
 }
 
 void BrowsingContext::Focus(ErrorResult& aError) {
-  ContentChild* cc = ContentChild::GetSingleton();
-  cc->SendWindowFocus(this);
+  if (ContentChild* cc = ContentChild::GetSingleton()) {
+    cc->SendWindowFocus(this);
+  } else if (ContentParent* cp = Canonical()->GetContentParent()) {
+    Unused << cp->SendWindowFocus(this);
+  }
 }
 
 void BrowsingContext::Blur(ErrorResult& aError) {
-  ContentChild* cc = ContentChild::GetSingleton();
-  cc->SendWindowBlur(this);
+  if (ContentChild* cc = ContentChild::GetSingleton()) {
+    cc->SendWindowBlur(this);
+  } else if (ContentParent* cp = Canonical()->GetContentParent()) {
+    Unused << cp->SendWindowBlur(this);
+  }
 }
 
 Nullable<WindowProxyHolder> BrowsingContext::GetTop(ErrorResult& aError) {
   // We never return null or throw an error, but the implementation in
   // nsGlobalWindow does and we need to use the same signature.
   return WindowProxyHolder(TopLevelBrowsingContext());
 }
 
 void BrowsingContext::GetOpener(JSContext* aCx,
                                 JS::MutableHandle<JS::Value> aOpener,
                                 ErrorResult& aError) const {
-  auto* opener = GetOpener();
+  RefPtr<BrowsingContext> opener = GetOpener();
   if (!opener) {
     aOpener.setNull();
     return;
   }
 
   if (!ToJSValue(aCx, WindowProxyHolder(opener), aOpener)) {
     aError.NoteJSContextException(aCx);
   }
@@ -670,24 +645,32 @@ void BrowsingContext::PostMessageMoz(JSC
   }
 
   ipc::StructuredCloneData message;
   message.Write(aCx, aMessage, transferArray, aError);
   if (NS_WARN_IF(aError.Failed())) {
     return;
   }
 
-  ContentChild* cc = ContentChild::GetSingleton();
   ClonedMessageData messageData;
-  if (!message.BuildClonedMessageDataForChild(cc, messageData)) {
-    aError.Throw(NS_ERROR_FAILURE);
-    return;
+  if (ContentChild* cc = ContentChild::GetSingleton()) {
+    if (!message.BuildClonedMessageDataForChild(cc, messageData)) {
+      aError.Throw(NS_ERROR_FAILURE);
+      return;
+    }
+
+    cc->SendWindowPostMessage(this, messageData, data);
+  } else if (ContentParent* cp = Canonical()->GetContentParent()) {
+    if (!message.BuildClonedMessageDataForParent(cp, messageData)) {
+      aError.Throw(NS_ERROR_FAILURE);
+      return;
+    }
+
+    Unused << cp->SendWindowPostMessage(this, messageData, data);
   }
-
-  cc->SendWindowPostMessage(this, messageData, data);
 }
 
 void BrowsingContext::PostMessageMoz(JSContext* aCx,
                                      JS::Handle<JS::Value> aMessage,
                                      const WindowPostMessageOptions& aOptions,
                                      nsIPrincipal& aSubjectPrincipal,
                                      ErrorResult& aError) {
   PostMessageMoz(aCx, aMessage, aOptions.mTargetOrigin, aOptions.mTransfer,
@@ -703,17 +686,47 @@ void BrowsingContext::Transaction::Commi
     for (auto iter = aBrowsingContext->Group()->ContentParentsIter();
          !iter.Done(); iter.Next()) {
       nsRefPtrHashKey<ContentParent>* entry = iter.Get();
       Unused << entry->GetKey()->SendCommitBrowsingContextTransaction(
           aBrowsingContext, *this);
     }
   }
 
-  Apply(aBrowsingContext);
+  Apply(aBrowsingContext, nullptr);
+}
+
+void BrowsingContext::Transaction::Apply(BrowsingContext* aBrowsingContext,
+                                         ContentParent* aSource) {
+#define MOZ_BC_FIELD(name, ...)                         \
+  if (m##name) {                                        \
+    aBrowsingContext->WillSet##name(*m##name, aSource); \
+    aBrowsingContext->m##name = std::move(*m##name);    \
+    aBrowsingContext->DidSet##name(aSource);            \
+    m##name.reset();                                    \
+  }
+#include "mozilla/dom/BrowsingContextFieldList.h"
+}
+
+already_AddRefed<BrowsingContext> BrowsingContext::IPCInitializer::GetParent() {
+  RefPtr<BrowsingContext> parent;
+  if (mParentId != 0) {
+    parent = BrowsingContext::Get(mParentId);
+    MOZ_RELEASE_ASSERT(parent);
+  }
+  return parent.forget();
+}
+
+already_AddRefed<BrowsingContext> BrowsingContext::IPCInitializer::GetOpener() {
+  RefPtr<BrowsingContext> opener;
+  if (mOpenerId != 0) {
+    opener = BrowsingContext::Get(mOpenerId);
+    MOZ_RELEASE_ASSERT(opener);
+  }
+  return opener.forget();
 }
 
 void BrowsingContext::LocationProxy::SetHref(const nsAString& aHref,
                                              nsIPrincipal& aSubjectPrincipal,
                                              ErrorResult& aError) {
   nsPIDOMWindowOuter* win = GetBrowsingContext()->GetDOMWindow();
   if (!win || !win->GetLocation()) {
     aError.Throw(NS_ERROR_FAILURE);
@@ -773,28 +786,58 @@ bool IPDLParamTraits<dom::BrowsingContex
   }
 
   return aResult != nullptr;
 }
 
 void IPDLParamTraits<dom::BrowsingContext::Transaction>::Write(
     IPC::Message* aMessage, IProtocol* aActor,
     const dom::BrowsingContext::Transaction& aTransaction) {
-  void_t sentinel;
-  const dom::BrowsingContext::Transaction* transaction = &aTransaction;
-  auto tuple = mozilla::Tie(
-      MOZ_FOR_EACH_SYNCED_BC_FIELD(MOZ_SYNCED_BC_FIELD_ARGUMENT, sentinel));
-
-  WriteIPDLParam(aMessage, aActor, tuple);
+#define MOZ_BC_FIELD(name, ...) \
+  WriteIPDLParam(aMessage, aActor, aTransaction.m##name);
+#include "mozilla/dom/BrowsingContextFieldList.h"
 }
 
 bool IPDLParamTraits<dom::BrowsingContext::Transaction>::Read(
     const IPC::Message* aMessage, PickleIterator* aIterator, IProtocol* aActor,
     dom::BrowsingContext::Transaction* aTransaction) {
-  void_t sentinel;
-  dom::BrowsingContext::Transaction* transaction = aTransaction;
-  auto tuple = mozilla::Tie(
-      MOZ_FOR_EACH_SYNCED_BC_FIELD(MOZ_SYNCED_BC_FIELD_ARGUMENT, sentinel));
-  return ReadIPDLParam(aMessage, aIterator, aActor, &tuple);
+#define MOZ_BC_FIELD(name, ...)                                              \
+  if (!ReadIPDLParam(aMessage, aIterator, aActor, &aTransaction->m##name)) { \
+    return false;                                                            \
+  }
+#include "mozilla/dom/BrowsingContextFieldList.h"
+
+  return true;
+}
+
+void IPDLParamTraits<dom::BrowsingContext::IPCInitializer>::Write(
+    IPC::Message* aMessage, IProtocol* aActor,
+    const dom::BrowsingContext::IPCInitializer& aInit) {
+  // Write actor ID parameters.
+  WriteIPDLParam(aMessage, aActor, aInit.mId);
+  WriteIPDLParam(aMessage, aActor, aInit.mParentId);
+
+  // Write other synchronized fields.
+#define MOZ_BC_FIELD(name, ...) WriteIPDLParam(aMessage, aActor, aInit.m##name);
+#include "mozilla/dom/BrowsingContextFieldList.h"
+}
+
+bool IPDLParamTraits<dom::BrowsingContext::IPCInitializer>::Read(
+    const IPC::Message* aMessage, PickleIterator* aIterator, IProtocol* aActor,
+    dom::BrowsingContext::IPCInitializer* aInit) {
+  // Read actor ID parameters.
+  if (!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mId) ||
+      !ReadIPDLParam(aMessage, aIterator, aActor, &aInit->mParentId)) {
+    return false;
+  }
+
+  // Read other synchronized fields.
+#define MOZ_BC_FIELD(name, ...)                                       \
+  if (!ReadIPDLParam(aMessage, aIterator, aActor, &aInit->m##name)) { \
+    return false;                                                     \
+  }
+#include "mozilla/dom/BrowsingContextFieldList.h"
+
+  return true;
 }
 
 }  // namespace ipc
 }  // namespace mozilla
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -37,89 +37,44 @@ class LogModule;
 namespace ipc {
 class IProtocol;
 
 template <typename T>
 struct IPDLParamTraits;
 }  // namespace ipc
 
 namespace dom {
+class BrowsingContent;
 class BrowsingContextGroup;
 class CanonicalBrowsingContext;
 class ContentParent;
 template <typename>
 struct Nullable;
 template <typename T>
 class Sequence;
 struct WindowPostMessageOptions;
 class WindowProxyHolder;
 
-// MOZ_FOR_EACH_SYNCED_FIELD declares BrowsingContext fields that need
-// to be synced to the synced versions of BrowsingContext in parent
-// and child processes. To add a new field for syncing add a line:
-//
-// declare(name of new field, storage type, parameter type)
-//
-// before __VA_ARGS__. This will declare a private member with the
-// supplied name prepended with 'm'. If the field needs to be
-// initialized in the constructor, then that will have to be done
-// manually, and of course keeping the same order as below.
-//
-// At all times the last line below should be __VA_ARGS__, since that
-// acts as a sentinel for callers of MOZ_FOR_EACH_SYNCED_FIELD.
-
-// clang-format off
-#define MOZ_FOR_EACH_SYNCED_BC_FIELD(declare, ...)        \
-  declare(Name, nsString, nsAString)                   \
-  declare(Closed, bool, bool)                          \
-  declare(CrossOriginPolicy, nsILoadInfo::CrossOriginPolicy, nsILoadInfo::CrossOriginPolicy) \
-  __VA_ARGS__
-// clang-format on
+class BrowsingContextBase {
+ protected:
+  BrowsingContextBase() {
+    // default-construct each field.
+#define MOZ_BC_FIELD(name, type) m##name = type();
+#include "mozilla/dom/BrowsingContextFieldList.h"
+  }
+  ~BrowsingContextBase() = default;
 
-#define MOZ_SYNCED_BC_FIELD_NAME(name, ...) m##name
-#define MOZ_SYNCED_BC_FIELD_ARGUMENT(name, type, atype) \
-  transaction->MOZ_SYNCED_BC_FIELD_NAME(name),
-#define MOZ_SYNCED_BC_FIELD_GETTER(name, type, atype) \
-  const type& Get##name() const { return MOZ_SYNCED_BC_FIELD_NAME(name); }
-#define MOZ_SYNCED_BC_FIELD_SETTER(name, type, atype) \
-  void Set##name(const atype& aValue) {               \
-    Transaction t;                                    \
-    t.MOZ_SYNCED_BC_FIELD_NAME(name).emplace(aValue); \
-    t.Commit(this);                                   \
-  }
-#define MOZ_SYNCED_BC_FIELD_MEMBER(name, type, atype) \
-  type MOZ_SYNCED_BC_FIELD_NAME(name);
-#define MOZ_SYNCED_BC_FIELD_MAYBE_MEMBER(name, type, atype) \
-  mozilla::Maybe<type> MOZ_SYNCED_BC_FIELD_NAME(name);
-#define MOZ_SYNCED_BC_FIELD_APPLIER(name, type, atype) \
-  if (MOZ_SYNCED_BC_FIELD_NAME(name)) {                \
-    aOwner->MOZ_SYNCED_BC_FIELD_NAME(name) =           \
-        std::move(*MOZ_SYNCED_BC_FIELD_NAME(name));    \
-    MOZ_SYNCED_BC_FIELD_NAME(name).reset();            \
-  }
-
-#define MOZ_SYNCED_BC_FIELDS                                              \
- public:                                                                  \
-  MOZ_FOR_EACH_SYNCED_BC_FIELD(MOZ_SYNCED_BC_FIELD_GETTER)                \
-  MOZ_FOR_EACH_SYNCED_BC_FIELD(MOZ_SYNCED_BC_FIELD_SETTER)                \
-  class Transaction {                                                     \
-   public:                                                                \
-    void Commit(BrowsingContext* aOwner);                                 \
-    void Apply(BrowsingContext* aOwner) {                                 \
-      MOZ_FOR_EACH_SYNCED_BC_FIELD(MOZ_SYNCED_BC_FIELD_APPLIER)           \
-      return; /* without this return clang-format messes up formatting */ \
-    }                                                                     \
-                                                                          \
-    MOZ_FOR_EACH_SYNCED_BC_FIELD(MOZ_SYNCED_BC_FIELD_MAYBE_MEMBER)        \
-   private:                                                               \
-    friend struct mozilla::ipc::IPDLParamTraits<Transaction>;             \
-  };                                                                      \
-                                                                          \
- private:                                                                 \
-  MOZ_FOR_EACH_SYNCED_BC_FIELD(MOZ_SYNCED_BC_FIELD_MEMBER)
+#define MOZ_BC_FIELD(name, type)                                    \
+  type m##name;                                                     \
+                                                                    \
+  /* shadow to validate fields. aSource is setter process or null*/ \
+  void WillSet##name(type const& aValue, ContentParent* aSource) {} \
+  void DidSet##name(ContentParent* aSource) {}
+#include "mozilla/dom/BrowsingContextFieldList.h"
+};
 
 // BrowsingContext, in this context, is the cross process replicated
 // environment in which information about documents is stored. In
 // particular the tree structure of nested browsing contexts is
 // represented by the tree of BrowsingContexts.
 //
 // The tree of BrowsingContexts is created in step with its
 // corresponding nsDocShell, and when nsDocShells are connected
@@ -129,20 +84,18 @@ class WindowProxyHolder;
 // BrowsingContext tree for a tab, in both the parent and the child
 // process.
 //
 // Trees of BrowsingContexts should only ever contain nodes of the
 // same BrowsingContext::Type. This is enforced by asserts in the
 // BrowsingContext::Create* methods.
 class BrowsingContext : public nsWrapperCache,
                         public SupportsWeakPtr<BrowsingContext>,
-                        public LinkedListElement<RefPtr<BrowsingContext>> {
-  // Do not declare members above MOZ_SYNCED_BC_FIELDS
-  MOZ_SYNCED_BC_FIELDS
-
+                        public LinkedListElement<RefPtr<BrowsingContext>>,
+                        public BrowsingContextBase {
  public:
   enum class Type { Chrome, Content };
 
   static void Init();
   static LogModule* GetLog();
   static void CleanupContexts(uint64_t aProcessId);
 
   // Look up a BrowsingContext in the current process by ID.
@@ -152,69 +105,70 @@ class BrowsingContext : public nsWrapper
   }
 
   // Create a brand-new BrowsingContext object.
   static already_AddRefed<BrowsingContext> Create(BrowsingContext* aParent,
                                                   BrowsingContext* aOpener,
                                                   const nsAString& aName,
                                                   Type aType);
 
-  // Create a BrowsingContext object from over IPC.
-  static already_AddRefed<BrowsingContext> CreateFromIPC(
-      BrowsingContext* aParent, BrowsingContext* aOpener,
-      const nsAString& aName, uint64_t aId, ContentParent* aOriginProcess);
-
   // Cast this object to a canonical browsing context, and return it.
   CanonicalBrowsingContext* Canonical();
 
+  // Is the most recent Document in this BrowsingContext loaded within this
+  // process? This may be true with a null mDocShell after the Window has been
+  // closed.
+  bool IsInProcess() const { return mIsInProcess; }
+
   // Get the DocShell for this BrowsingContext if it is in-process, or
   // null if it's not.
   nsIDocShell* GetDocShell() { return mDocShell; }
   void SetDocShell(nsIDocShell* aDocShell);
 
   // Get the outer window object for this BrowsingContext if it is in-process
   // and still has a docshell, or null otherwise.
   nsPIDOMWindowOuter* GetDOMWindow() const {
     return mDocShell ? mDocShell->GetWindow() : nullptr;
   }
 
   // Attach the current BrowsingContext to its parent, in both the child and the
   // parent process. BrowsingContext objects are created attached by default, so
   // this method need only be called when restoring cached BrowsingContext
   // objects.
-  void Attach();
+  void Attach(bool aFromIPC = false);
 
   // Detach the current BrowsingContext from its parent, in both the
   // child and the parent process.
-  void Detach();
+  void Detach(bool aFromIPC = false);
 
   // Remove all children from the current BrowsingContext and cache
   // them to allow them to be attached again.
-  void CacheChildren();
+  void CacheChildren(bool aFromIPC = false);
 
   // Determine if the current BrowsingContext was 'cached' by the logic in
   // CacheChildren.
   bool IsCached();
 
   const nsString& Name() const { return mName; }
   void GetName(nsAString& aName) { aName = mName; }
   bool NameEquals(const nsAString& aName) { return mName.Equals(aName); }
 
   bool IsContent() const { return mType == Type::Content; }
 
   uint64_t Id() const { return mBrowsingContextId; }
 
-  BrowsingContext* GetParent() { return mParent; }
+  BrowsingContext* GetParent() const { return mParent; }
+
+  already_AddRefed<BrowsingContext> GetOpener() const { return Get(mOpenerId); }
+  void SetOpener(BrowsingContext* aOpener) {
+    SetOpenerId(aOpener ? aOpener->Id() : 0);
+  }
 
   void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);
 
-  BrowsingContext* GetOpener() const { return mOpener; }
-
-  void SetOpener(BrowsingContext* aOpener);
-
   BrowsingContextGroup* Group() { return mGroup; }
 
   // Using the rules for choosing a browsing context we try to find
   // the browsing context with the given name in the set of
   // transitively reachable browsing contexts. Performs access control
   // with regards to this.
   // See
   // https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name.
@@ -238,21 +192,16 @@ class BrowsingContext : public nsWrapper
   // by user gesture, and we would set the flag in the top level browsing
   // context.
   void NotifyUserGestureActivation();
 
   // This function would be called when we want to reset the user gesture
   // activation flag of the top level browsing context.
   void NotifyResetUserGestureActivation();
 
-  // These functions would only be called in the top level browsing context.
-  // They would set/reset the user gesture activation flag.
-  void SetUserGestureActivation();
-  void ResetUserGestureActivation();
-
   // Return true if it corresponding document is activated by user gesture.
   bool GetUserGestureActivation();
 
   // Return the window proxy object that corresponds to this browsing context.
   inline JSObject* GetWindowProxy() const { return mWindowProxy; }
   // Set the window proxy object that corresponds to this browsing context.
   void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) {
     mWindowProxy = aWindowProxy;
@@ -260,16 +209,25 @@ class BrowsingContext : public nsWrapper
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(BrowsingContext)
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BrowsingContext)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(BrowsingContext)
 
   using Children = nsTArray<RefPtr<BrowsingContext>>;
   const Children& GetChildren() { return mChildren; }
 
+  // Perform a pre-order walk of this BrowsingContext subtree.
+  template <typename Func>
+  void PreOrderWalk(Func&& aCallback) {
+    aCallback(this);
+    for (auto& child : GetChildren()) {
+      child->PreOrderWalk(aCallback);
+    }
+  }
+
   // Window APIs that are cross-origin-accessible (from the HTML spec).
   BrowsingContext* Window() { return Self(); }
   BrowsingContext* Self() { return this; }
   void Location(JSContext* aCx, JS::MutableHandle<JSObject*> aLocation,
                 ErrorResult& aError);
   void Close(CallerType aCallerType, ErrorResult& aError);
   bool GetClosed(ErrorResult&) { return mClosed; }
   void Focus(ErrorResult& aError);
@@ -285,25 +243,94 @@ class BrowsingContext : public nsWrapper
                       const Sequence<JSObject*>& aTransfer,
                       nsIPrincipal& aSubjectPrincipal, ErrorResult& aError);
   void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                       const WindowPostMessageOptions& aOptions,
                       nsIPrincipal& aSubjectPrincipal, ErrorResult& aError);
 
   JSObject* WrapObject(JSContext* aCx);
 
-  nsILoadInfo::CrossOriginPolicy CrossOriginPolicy() {
-    return mCrossOriginPolicy;
+  /**
+   * Transaction object. This object is used to specify and then commit
+   * modifications to synchronized fields in BrowsingContexts.
+   */
+  class Transaction {
+   public:
+    // Apply the changes from this transaction to the specified BrowsingContext
+    // in all processes. This method will call the correct `WillSet` and
+    // `DidSet` methods, as well as move the value.
+    //
+    // NOTE: This method mutates `this`, resetting all members to `Nothing()`
+    void Commit(BrowsingContext* aOwner);
+
+    // You probably don't want to directly call this method - instead call
+    // `Commit`, which will perform the necessary synchronization.
+    //
+    // |aSource| is the ContentParent which is performing the mutation in the
+    // parent process.
+    void Apply(BrowsingContext* aOwner, ContentParent* aSource);
+
+#define MOZ_BC_FIELD(name, type) mozilla::Maybe<type> m##name;
+#include "mozilla/dom/BrowsingContextFieldList.h"
+
+   private:
+    friend struct mozilla::ipc::IPDLParamTraits<Transaction>;
+  };
+
+#define MOZ_BC_FIELD(name, type)                        \
+  template <typename... Args>                           \
+  void Set##name(Args&&... aValue) {                    \
+    Transaction txn;                                    \
+    txn.m##name.emplace(std::forward<Args>(aValue)...); \
+    txn.Commit(this);                                   \
+  }                                                     \
+                                                        \
+  type const& Get##name() const { return m##name; }
+#include "mozilla/dom/BrowsingContextFieldList.h"
+
+  /**
+   * Information required to initialize a BrowsingContext in another process.
+   * This object may be serialized over IPC.
+   */
+  struct IPCInitializer {
+    uint64_t mId;
+
+    // IDs are used for Parent and Opener to allow for this object to be
+    // deserialized before other BrowsingContext in the BrowsingContextGroup
+    // have been initialized.
+    uint64_t mParentId;
+    already_AddRefed<BrowsingContext> GetParent();
+    already_AddRefed<BrowsingContext> GetOpener();
+
+    // Include each field, skipping mOpener, as we want to handle it
+    // separately.
+#define MOZ_BC_FIELD(name, type) type m##name;
+#include "mozilla/dom/BrowsingContextFieldList.h"
+  };
+
+  // Create an IPCInitializer object for this BrowsingContext.
+  IPCInitializer GetIPCInitializer() {
+    IPCInitializer init;
+    init.mId = Id();
+    init.mParentId = mParent ? mParent->Id() : 0;
+
+#define MOZ_BC_FIELD(name, type) init.m##name = m##name;
+#include "mozilla/dom/BrowsingContextFieldList.h"
+    return init;
   }
 
+  // Create a BrowsingContext object from over IPC.
+  static already_AddRefed<BrowsingContext> CreateFromIPC(
+      IPCInitializer&& aInitializer, BrowsingContextGroup* aGroup,
+      ContentParent* aOriginProcess);
+
  protected:
   virtual ~BrowsingContext();
-  BrowsingContext(BrowsingContext* aParent, BrowsingContext* aOpener,
-                  const nsAString& aName, uint64_t aBrowsingContextId,
-                  Type aType);
+  BrowsingContext(BrowsingContext* aParent, BrowsingContextGroup* aGroup,
+                  uint64_t aBrowsingContextId, Type aType);
 
  private:
   // Find the special browsing context if aName is '_self', '_parent',
   // '_top', but not '_blank'. The latter is handled in FindWithName
   BrowsingContext* FindWithSpecialName(const nsAString& aName);
 
   // Find a browsing context in the subtree rooted at 'this' Doesn't
   // consider the special names, '_self', '_parent', '_top', or
@@ -358,52 +385,62 @@ class BrowsingContext : public nsWrapper
    private:
     friend class RemoteLocationProxy;
     BrowsingContext* GetBrowsingContext() {
       return reinterpret_cast<BrowsingContext*>(
           uintptr_t(this) - offsetof(BrowsingContext, mLocation));
     }
   };
 
+  // Ensure that opener is in the same BrowsingContextGroup.
+  void WillSetOpener(const uint64_t& aValue, ContentParent* aSource) {
+    if (aValue != 0) {
+      RefPtr<BrowsingContext> opener = Get(aValue);
+      MOZ_RELEASE_ASSERT(opener && opener->Group() == Group());
+    }
+  }
+
   // Type of BrowsingContent
   const Type mType;
 
   // Unique id identifying BrowsingContext
   const uint64_t mBrowsingContextId;
 
   RefPtr<BrowsingContextGroup> mGroup;
   RefPtr<BrowsingContext> mParent;
   Children mChildren;
-  WeakPtr<BrowsingContext> mOpener;
   nsCOMPtr<nsIDocShell> mDocShell;
+
   // This is not a strong reference, but using a JS::Heap for that should be
   // fine. The JSObject stored in here should be a proxy with a
   // nsOuterWindowProxy handler, which will update the pointer from its
   // objectMoved hook and clear it from its finalize hook.
   JS::Heap<JSObject*> mWindowProxy;
   LocationProxy mLocation;
 
-  // This flag is only valid in the top level browsing context, it indicates
-  // whether the corresponding document has been activated by user gesture.
-  bool mIsActivatedByUserGesture;
+  // Is the most recent Document in this BrowsingContext loaded within this
+  // process? This may be true with a null mDocShell after the Window has been
+  // closed.
+  bool mIsInProcess : 1;
 };
 
 /**
  * Gets a WindowProxy object for a BrowsingContext that lives in a different
  * process (creating the object if it doesn't already exist). The WindowProxy
  * object will be in the compartment that aCx is currently in. This should only
  * be called if aContext doesn't hold a docshell, otherwise the BrowsingContext
  * lives in this process, and a same-process WindowProxy should be used (see
  * nsGlobalWindowOuter). This should only be called by bindings code, ToJSValue
  * is the right API to get a WindowProxy for a BrowsingContext.
  */
 extern bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
                                       JS::MutableHandle<JSObject*> aRetVal);
 
 typedef BrowsingContext::Transaction BrowsingContextTransaction;
+typedef BrowsingContext::IPCInitializer BrowsingContextInitializer;
 
 }  // namespace dom
 
 // Allow sending BrowsingContext objects over IPC.
 namespace ipc {
 template <>
 struct IPDLParamTraits<dom::BrowsingContext> {
   static void Write(IPC::Message* aMsg, IProtocol* aActor,
@@ -417,12 +454,22 @@ struct IPDLParamTraits<dom::BrowsingCont
   static void Write(IPC::Message* aMessage, IProtocol* aActor,
                     const dom::BrowsingContext::Transaction& aTransaction);
 
   static bool Read(const IPC::Message* aMessage, PickleIterator* aIterator,
                    IProtocol* aActor,
                    dom::BrowsingContext::Transaction* aTransaction);
 };
 
+template <>
+struct IPDLParamTraits<dom::BrowsingContext::IPCInitializer> {
+  static void Write(IPC::Message* aMessage, IProtocol* aActor,
+                    const dom::BrowsingContext::IPCInitializer& aInitializer);
+
+  static bool Read(const IPC::Message* aMessage, PickleIterator* aIterator,
+                   IProtocol* aActor,
+                   dom::BrowsingContext::IPCInitializer* aInitializer);
+};
+
 }  // namespace ipc
 }  // namespace mozilla
 
 #endif  // !defined(mozilla_dom_BrowsingContext_h)
new file mode 100644
--- /dev/null
+++ b/docshell/base/BrowsingContextFieldList.h
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+MOZ_BC_FIELD(Name, nsString)
+MOZ_BC_FIELD(Closed, bool)
+MOZ_BC_FIELD(CrossOriginPolicy, nsILoadInfo::CrossOriginPolicy)
+
+// The current opener for this BrowsingContext. This is a weak reference, and
+// stored as the opener ID.
+MOZ_BC_FIELD(OpenerId, uint64_t)
+
+// Toplevel browsing contexts only. This field controls whether the browsing
+// context is currently considered to be activated by a gesture.
+MOZ_BC_FIELD(IsActivatedByUserGesture, bool)
+
+#undef MOZ_BC_FIELD
+#undef MOZ_BC_FIELD_SKIP_OPENER
--- a/docshell/base/BrowsingContextGroup.cpp
+++ b/docshell/base/BrowsingContextGroup.cpp
@@ -32,16 +32,50 @@ void BrowsingContextGroup::Subscribe(Con
 }
 
 void BrowsingContextGroup::Unsubscribe(ContentParent* aOriginProcess) {
   MOZ_DIAGNOSTIC_ASSERT(aOriginProcess);
   mSubscribers.RemoveEntry(aOriginProcess);
   aOriginProcess->OnBrowsingContextGroupUnsubscribe(this);
 }
 
+void BrowsingContextGroup::EnsureSubscribed(ContentParent* aProcess) {
+  MOZ_DIAGNOSTIC_ASSERT(aProcess);
+  if (mSubscribers.Contains(aProcess)) {
+    return;
+  }
+
+  // Subscribe to the BrowsingContext, and send down initial state!
+  Subscribe(aProcess);
+
+  // Iterate over each of our browsing contexts, locating those which are not in
+  // their parent's children list. We can then use those as starting points to
+  // get a pre-order walk of each tree.
+  nsTArray<BrowsingContext::IPCInitializer> inits(mContexts.Count());
+  for (auto iter = mContexts.Iter(); !iter.Done(); iter.Next()) {
+    auto* context = iter.Get()->GetKey();
+
+    // If we have a parent, and are in our parent's `Children` list, skip
+    // ourselves as we'll be found in the pre-order traversal of our parent.
+    if (context->GetParent() &&
+        context->GetParent()->GetChildren().IndexOf(context) !=
+            BrowsingContext::Children::NoIndex) {
+      continue;
+    }
+
+    // Add all elements to the list in pre-order.
+    context->PreOrderWalk([&](BrowsingContext* aContext) {
+      inits.AppendElement(aContext->GetIPCInitializer());
+    });
+  }
+
+  // Send all of our contexts to the target content process.
+  Unused << aProcess->SendRegisterBrowsingContextGroup(inits);
+}
+
 BrowsingContextGroup::~BrowsingContextGroup() {
   for (auto iter = mSubscribers.Iter(); !iter.Done(); iter.Next()) {
     nsRefPtrHashKey<ContentParent>* entry = iter.Get();
     entry->GetKey()->OnBrowsingContextGroupUnsubscribe(this);
   }
 }
 
 nsISupports* BrowsingContextGroup::GetParentObject() const {
--- a/docshell/base/BrowsingContextGroup.h
+++ b/docshell/base/BrowsingContextGroup.h
@@ -38,31 +38,56 @@ class BrowsingContextGroup final : publi
   bool Contains(BrowsingContext* aContext);
   void Register(BrowsingContext* aContext);
   void Unregister(BrowsingContext* aContext);
 
   // Interact with the list of ContentParents
   void Subscribe(ContentParent* aOriginProcess);
   void Unsubscribe(ContentParent* aOriginProcess);
 
+  // Force the given ContentParent to subscribe to our BrowsingContextGroup.
+  void EnsureSubscribed(ContentParent* aProcess);
+
   ContentParents::Iterator ContentParentsIter() { return mSubscribers.Iter(); }
 
   // Get a reference to the list of toplevel contexts in this
   // BrowsingContextGroup.
   BrowsingContext::Children& Toplevels() { return mToplevels; }
   void GetToplevels(BrowsingContext::Children& aToplevels) {
     aToplevels.AppendElements(mToplevels);
   }
 
   nsISupports* GetParentObject() const;
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
   BrowsingContextGroup() = default;
 
+  static already_AddRefed<BrowsingContextGroup> Select(
+      BrowsingContext* aParent, BrowsingContext* aOpener) {
+    if (aParent) {
+      return do_AddRef(aParent->Group());
+    }
+    if (aOpener) {
+      return do_AddRef(aOpener->Group());
+    }
+    return MakeAndAddRef<BrowsingContextGroup>();
+  }
+
+  static already_AddRefed<BrowsingContextGroup> Select(uint64_t aParentId,
+                                                       uint64_t aOpenerId) {
+    RefPtr<BrowsingContext> parent = BrowsingContext::Get(aParentId);
+    MOZ_RELEASE_ASSERT(parent || aParentId == 0);
+
+    RefPtr<BrowsingContext> opener = BrowsingContext::Get(aOpenerId);
+    MOZ_RELEASE_ASSERT(opener || aOpenerId == 0);
+
+    return Select(parent, opener);
+  }
+
  private:
   friend class CanonicalBrowsingContext;
 
   ~BrowsingContextGroup();
 
   // A BrowsingContextGroup contains a series of BrowsingContext objects. They
   // are addressed using a hashtable to avoid linear lookup when adding or
   // removing elements from the set.
--- a/docshell/base/CanonicalBrowsingContext.cpp
+++ b/docshell/base/CanonicalBrowsingContext.cpp
@@ -3,32 +3,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/CanonicalBrowsingContext.h"
 
 #include "mozilla/dom/BrowsingContextGroup.h"
 #include "mozilla/dom/WindowGlobalParent.h"
+#include "mozilla/dom/ContentProcessManager.h"
 
 namespace mozilla {
 namespace dom {
 
 extern mozilla::LazyLogModule gUserInteractionPRLog;
 
 #define USER_ACTIVATION_LOG(msg, ...) \
   MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
 
 CanonicalBrowsingContext::CanonicalBrowsingContext(BrowsingContext* aParent,
-                                                   BrowsingContext* aOpener,
-                                                   const nsAString& aName,
+                                                   BrowsingContextGroup* aGroup,
                                                    uint64_t aBrowsingContextId,
                                                    uint64_t aProcessId,
                                                    BrowsingContext::Type aType)
-    : BrowsingContext(aParent, aOpener, aName, aBrowsingContextId, aType),
+    : BrowsingContext(aParent, aGroup, aBrowsingContextId, aType),
       mProcessId(aProcessId) {
   // You are only ever allowed to create CanonicalBrowsingContexts in the
   // parent process.
   MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
 }
 
 /* static */
 already_AddRefed<CanonicalBrowsingContext> CanonicalBrowsingContext::Get(
@@ -39,22 +39,32 @@ already_AddRefed<CanonicalBrowsingContex
 
 /* static */
 CanonicalBrowsingContext* CanonicalBrowsingContext::Cast(
     BrowsingContext* aContext) {
   MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
   return static_cast<CanonicalBrowsingContext*>(aContext);
 }
 
-/* static */ const CanonicalBrowsingContext* CanonicalBrowsingContext::Cast(
+/* static */
+const CanonicalBrowsingContext* CanonicalBrowsingContext::Cast(
     const BrowsingContext* aContext) {
   MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
   return static_cast<const CanonicalBrowsingContext*>(aContext);
 }
 
+ContentParent* CanonicalBrowsingContext::GetContentParent() const {
+  if (mProcessId == 0) {
+    return nullptr;
+  }
+
+  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
+  return cpm->GetContentProcessById(ContentParentId(mProcessId));
+}
+
 void CanonicalBrowsingContext::GetWindowGlobals(
     nsTArray<RefPtr<WindowGlobalParent>>& aWindows) {
   aWindows.SetCapacity(mWindowGlobals.Count());
   for (auto iter = mWindowGlobals.Iter(); !iter.Done(); iter.Next()) {
     aWindows.AppendElement(iter.Get()->GetKey());
   }
 }
 
@@ -79,42 +89,30 @@ void CanonicalBrowsingContext::Unregiste
 void CanonicalBrowsingContext::SetCurrentWindowGlobal(
     WindowGlobalParent* aGlobal) {
   MOZ_ASSERT(mWindowGlobals.Contains(aGlobal), "Global not registered!");
 
   // TODO: This should probably assert that the processes match.
   mCurrentWindowGlobal = aGlobal;
 }
 
+bool CanonicalBrowsingContext::ValidateTransaction(
+    const Transaction& aTransaction, ContentParent* aProcess) {
+  if (NS_WARN_IF(aProcess && mProcessId != aProcess->ChildID())) {
+    return false;
+  }
+
+  return true;
+}
+
 JSObject* CanonicalBrowsingContext::WrapObject(
     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
   return CanonicalBrowsingContext_Binding::Wrap(aCx, this, aGivenProto);
 }
 
-void CanonicalBrowsingContext::NotifySetUserGestureActivationFromIPC(
-    bool aIsUserGestureActivation) {
-  if (!mCurrentWindowGlobal) {
-    return;
-  }
-
-  if (aIsUserGestureActivation) {
-    SetUserGestureActivation();
-  } else {
-    ResetUserGestureActivation();
-  }
-
-  USER_ACTIVATION_LOG("Chrome browsing context 0x%08" PRIx64
-                      " would notify other browsing contexts for updating "
-                      "user gesture activation flag.",
-                      Id());
-  // XXX(alwu) : we need to sync the flag to other browsing contexts which are
-  // not in the same child process where the flag was set. Will implement that
-  // in bug1519229.
-}
-
 void CanonicalBrowsingContext::Traverse(
     nsCycleCollectionTraversalCallback& cb) {
   CanonicalBrowsingContext* tmp = this;
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobals);
 }
 
 void CanonicalBrowsingContext::Unlink() {
   CanonicalBrowsingContext* tmp = this;
--- a/docshell/base/CanonicalBrowsingContext.h
+++ b/docshell/base/CanonicalBrowsingContext.h
@@ -29,16 +29,19 @@ class CanonicalBrowsingContext final : p
   static already_AddRefed<CanonicalBrowsingContext> Get(uint64_t aId);
   static CanonicalBrowsingContext* Cast(BrowsingContext* aContext);
   static const CanonicalBrowsingContext* Cast(const BrowsingContext* aContext);
 
   bool IsOwnedByProcess(uint64_t aProcessId) const {
     return mProcessId == aProcessId;
   }
   uint64_t OwnerProcessId() const { return mProcessId; }
+  ContentParent* GetContentParent() const;
+
+  void SetOwnerProcessId(uint64_t aProcessId) { mProcessId = aProcessId; }
 
   void GetWindowGlobals(nsTArray<RefPtr<WindowGlobalParent>>& aWindows);
 
   // Called by WindowGlobalParent to register and unregister window globals.
   void RegisterWindowGlobal(WindowGlobalParent* aGlobal);
   void UnregisterWindowGlobal(WindowGlobalParent* aGlobal);
 
   // The current active WindowGlobal.
@@ -52,24 +55,30 @@ class CanonicalBrowsingContext final : p
 
   // This functions would set/reset its user gesture activation flag and then
   // notify other browsing contexts which are not the one related with the
   // current window global to set/reset the flag. (the corresponding browsing
   // context of the current global window has been set/reset before calling this
   // function)
   void NotifySetUserGestureActivationFromIPC(bool aIsUserGestureActivation);
 
+  // Validate that the given process is allowed to perform the given
+  // transaction. aSource is |nullptr| if set in the parent process.
+  bool ValidateTransaction(const Transaction& aTransaction,
+                           ContentParent* aSource);
+
  protected:
   void Traverse(nsCycleCollectionTraversalCallback& cb);
   void Unlink();
 
   using Type = BrowsingContext::Type;
-  CanonicalBrowsingContext(BrowsingContext* aParent, BrowsingContext* aOpener,
-                           const nsAString& aName, uint64_t aBrowsingContextId,
-                           uint64_t aProcessId, Type aType = Type::Chrome);
+  CanonicalBrowsingContext(BrowsingContext* aParent,
+                           BrowsingContextGroup* aGroup,
+                           uint64_t aBrowsingContextId, uint64_t aProcessId,
+                           Type aType);
 
  private:
   friend class BrowsingContext;
 
   // XXX(farre): Store a ContentParent pointer here rather than mProcessId?
   // Indicates which process owns the docshell.
   uint64_t mProcessId;
 
--- a/docshell/base/moz.build
+++ b/docshell/base/moz.build
@@ -71,16 +71,17 @@ EXPORTS += [
 
 EXPORTS.mozilla += [
     'IHistory.h',
     'LoadContext.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'BrowsingContext.h',
+    'BrowsingContextFieldList.h',
     'BrowsingContextGroup.h',
     'CanonicalBrowsingContext.h',
     'ChildProcessChannelListener.h',
 ]
 
 UNIFIED_SOURCES += [
     'BrowsingContext.cpp',
     'BrowsingContextGroup.cpp',
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -1889,26 +1889,40 @@ bool nsFrameLoader::ShouldUseRemoteProce
                                     nsGkAtoms::_true, eCaseMatters);
 }
 
 static already_AddRefed<BrowsingContext> CreateBrowsingContext(
     BrowsingContext* aParentContext, BrowsingContext* aOpenerContext,
     const nsAString& aName, bool aIsContent) {
   // If we're content but our parent isn't, we're going to want to start a new
   // browsing context tree.
-  if (aIsContent && !aParentContext->IsContent()) {
+  if (aIsContent && aParentContext && !aParentContext->IsContent()) {
     aParentContext = nullptr;
   }
 
   BrowsingContext::Type type = aIsContent ? BrowsingContext::Type::Content
                                           : BrowsingContext::Type::Chrome;
 
   return BrowsingContext::Create(aParentContext, aOpenerContext, aName, type);
 }
 
+static void GetFrameName(Element* aOwnerContent, nsAString& aFrameName) {
+  int32_t namespaceID = aOwnerContent->GetNameSpaceID();
+  if (namespaceID == kNameSpaceID_XHTML && !aOwnerContent->IsInHTMLDocument()) {
+    aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, aFrameName);
+  } else {
+    aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, aFrameName);
+    // XXX if no NAME then use ID, after a transition period this will be
+    // changed so that XUL only uses ID too (bug 254284).
+    if (aFrameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
+      aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, aFrameName);
+    }
+  }
+}
+
 nsresult nsFrameLoader::MaybeCreateDocShell() {
   if (mDocShell) {
     return NS_OK;
   }
   if (IsRemoteFrame()) {
     return NS_OK;
   }
   NS_ENSURE_STATE(!mDestroyCalled);
@@ -1940,28 +1954,17 @@ nsresult nsFrameLoader::MaybeCreateDocSh
     return NS_ERROR_UNEXPECTED;
   }
 
   RefPtr<BrowsingContext> parentBC = parentDocShell->GetBrowsingContext();
   MOZ_ASSERT(parentBC, "docShell must have BrowsingContext");
 
   // Determine the frame name for the new browsing context.
   nsAutoString frameName;
-
-  int32_t namespaceID = mOwnerContent->GetNameSpaceID();
-  if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
-    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
-  } else {
-    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
-    // XXX if no NAME then use ID, after a transition period this will be
-    // changed so that XUL only uses ID too (bug 254284).
-    if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
-      mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
-    }
-  }
+  GetFrameName(mOwnerContent, frameName);
 
   // Check if our new context is chrome or content
   bool isContent = parentBC->IsContent() ||
                    mOwnerContent->AttrValueIs(kNameSpaceID_None, TypeAttrName(),
                                               nsGkAtoms::content, eIgnoreCase);
 
   // Force mozbrowser frames to always be content, even if the mozbrowser
   // interfaces are disabled.
@@ -2573,18 +2576,31 @@ bool nsFrameLoader::TryRemoteBrowser() {
       Unused << window->GetNextTabParentId(&nextTabParentId);
     }
   }
 
   nsCOMPtr<Element> ownerElement = mOwnerContent;
 
   // If we're in a content process, create a BrowserBridgeChild actor.
   if (XRE_IsContentProcess()) {
+    // Determine the frame name for the new browsing context.
+    nsAutoString frameName;
+    GetFrameName(mOwnerContent, frameName);
+
+    RefPtr<BrowsingContext> parentBC;
+    parentDocShell->GetBrowsingContext(getter_AddRefs(parentBC));
+    MOZ_ASSERT(parentBC, "docShell must have BrowsingContext");
+
+    // XXX(nika): due to limitations with Browsing Context Groups and multiple
+    // processes, we can't link up aParent yet! (Bug 1532661)
+    RefPtr<BrowsingContext> browsingContext =
+        CreateBrowsingContext(parentBC, nullptr, frameName, true);
+
     mBrowserBridgeChild = BrowserBridgeChild::Create(
-        this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
+        this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE), browsingContext);
     return !!mBrowserBridgeChild;
   }
 
   mRemoteBrowser =
       ContentParent::CreateBrowser(context, ownerElement, openerContentParent,
                                    sameTabGroupAs, nextTabParentId);
   if (!mRemoteBrowser) {
     return false;
@@ -3109,28 +3125,38 @@ already_AddRefed<mozilla::dom::Promise> 
 }
 
 already_AddRefed<nsITabParent> nsFrameLoader::GetTabParent() {
   return do_AddRef(mRemoteBrowser);
 }
 
 already_AddRefed<nsILoadContext> nsFrameLoader::LoadContext() {
   nsCOMPtr<nsILoadContext> loadContext;
-  if (IsRemoteFrame() && (mRemoteBrowser || TryRemoteBrowser())) {
-    loadContext = mRemoteBrowser->GetLoadContext();
+  if (IsRemoteFrame() &&
+      (mRemoteBrowser || mBrowserBridgeChild || TryRemoteBrowser())) {
+    if (mRemoteBrowser) {
+      loadContext = mRemoteBrowser->GetLoadContext();
+    } else {
+      loadContext = mBrowserBridgeChild->GetLoadContext();
+    }
   } else {
     loadContext = do_GetInterface(ToSupports(GetDocShell(IgnoreErrors())));
   }
   return loadContext.forget();
 }
 
 already_AddRefed<BrowsingContext> nsFrameLoader::GetBrowsingContext() {
   RefPtr<BrowsingContext> browsingContext;
-  if (IsRemoteFrame() && (mRemoteBrowser || TryRemoteBrowser())) {
-    browsingContext = mRemoteBrowser->GetBrowsingContext();
+  if (IsRemoteFrame() &&
+      (mRemoteBrowser || mBrowserBridgeChild || TryRemoteBrowser())) {
+    if (mRemoteBrowser) {
+      browsingContext = mRemoteBrowser->GetBrowsingContext();
+    } else {
+      browsingContext = mBrowserBridgeChild->GetBrowsingContext();
+    }
   } else if (GetDocShell(IgnoreErrors())) {
     browsingContext = nsDocShell::Cast(mDocShell)->GetBrowsingContext();
   }
   return browsingContext.forget();
 }
 
 void nsFrameLoader::InitializeBrowserAPI() {
   if (!OwnerIsMozBrowserFrame()) {
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -2477,20 +2477,21 @@ void nsGlobalWindowOuter::DetachFromDocS
   MaybeForgiveSpamCount();
   CleanUp();
 }
 
 void nsGlobalWindowOuter::SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
                                           bool aOriginalOpener) {
   nsWeakPtr opener = do_GetWeakReference(aOpener);
   if (opener == mOpener) {
-    MOZ_DIAGNOSTIC_ASSERT(
-        !aOpener || !aOpener->GetDocShell() ||
-        (GetBrowsingContext() &&
-         GetBrowsingContext()->GetOpener() == aOpener->GetBrowsingContext()));
+    MOZ_DIAGNOSTIC_ASSERT(!aOpener || !aOpener->GetDocShell() ||
+                          (GetBrowsingContext() &&
+                           aOpener->GetBrowsingContext() &&
+                           aOpener->GetBrowsingContext()->Id() ==
+                               GetBrowsingContext()->GetOpenerId()));
     return;
   }
 
   NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
                "aOriginalOpener is true, but not first call to "
                "SetOpenerWindow!");
   NS_ASSERTION(aOpener || !aOriginalOpener,
                "Shouldn't set mHadOriginalOpener if aOpener is null");
@@ -2503,17 +2504,18 @@ void nsGlobalWindowOuter::SetOpenerWindo
         !aOriginalOpener || !aOpener ||
         // TODO(farre): Allowing to set a closed or closing window as
         // opener is not ideal, since it won't have a docshell and
         // therefore no browsing context. This means that we're
         // effectively setting the browsing context opener to null and
         // the window opener to a closed window. This needs to be
         // cleaned up, see Bug 1511353.
         nsGlobalWindowOuter::Cast(aOpener)->IsClosedOrClosing() ||
-        aOpener->GetBrowsingContext() == GetBrowsingContext()->GetOpener());
+        aOpener->GetBrowsingContext()->Id() ==
+            GetBrowsingContext()->GetOpenerId());
     // TODO(farre): Here we really wish to only consider the case
     // where 'aOriginalOpener'. See bug 1509016.
     GetBrowsingContext()->SetOpener(aOpener ? aOpener->GetBrowsingContext()
                                             : nullptr);
   }
 
   // Check that the js visible opener matches! We currently don't depend on this
   // being true outside of nightly, so we disable the assertion in optimized
--- a/dom/bindings/ToJSValue.cpp
+++ b/dom/bindings/ToJSValue.cpp
@@ -64,17 +64,17 @@ bool ToJSValue(JSContext* aCx, Promise& 
 bool ToJSValue(JSContext* aCx, const WindowProxyHolder& aArgument,
                JS::MutableHandle<JS::Value> aValue) {
   BrowsingContext* bc = aArgument.get();
   if (!bc) {
     aValue.setNull();
     return true;
   }
   JS::Rooted<JSObject*> windowProxy(aCx);
-  if (bc->GetDocShell()) {
+  if (bc->IsInProcess()) {
     windowProxy = bc->GetWindowProxy();
     if (!windowProxy) {
       nsPIDOMWindowOuter* window = bc->GetDOMWindow();
       if (!window) {
         // Torn down enough that we should just return null.
         aValue.setNull();
         return true;
       }
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -424,17 +424,17 @@ nsresult FetchDriver::HttpFetch(
   rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, nullptr, ios);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (StaticPrefs::browser_tabs_remote_useCrossOriginPolicy()) {
     // Cross-Origin policy - bug 1525036
     nsILoadInfo::CrossOriginPolicy corsCredentials =
         nsILoadInfo::CROSS_ORIGIN_POLICY_NULL;
     if (mDocument && mDocument->GetBrowsingContext()) {
-      corsCredentials = mDocument->GetBrowsingContext()->CrossOriginPolicy();
+      corsCredentials = mDocument->GetBrowsingContext()->GetCrossOriginPolicy();
     }  // TODO Bug 1532287: else use mClientInfo
 
     if (mRequest->Mode() == RequestMode::No_cors &&
         corsCredentials != nsILoadInfo::CROSS_ORIGIN_POLICY_NULL) {
       mRequest->SetMode(RequestMode::Cors);
       mRequest->SetCredentialsMode(RequestCredentials::Same_origin);
       if (corsCredentials == nsILoadInfo::CROSS_ORIGIN_POLICY_USE_CREDENTIALS) {
         mRequest->SetCredentialsMode(RequestCredentials::Include);
--- a/dom/ipc/BrowserBridgeChild.cpp
+++ b/dom/ipc/BrowserBridgeChild.cpp
@@ -1,51 +1,57 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/BrowserBridgeChild.h"
+#include "mozilla/dom/BrowsingContext.h"
 #include "nsFocusManager.h"
 #include "nsFrameLoader.h"
 #include "nsFrameLoaderOwner.h"
 #include "nsQueryObject.h"
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace dom {
 
-BrowserBridgeChild::BrowserBridgeChild(nsFrameLoader* aFrameLoader)
-    : mLayersId{0}, mIPCOpen(true), mFrameLoader(aFrameLoader) {}
+BrowserBridgeChild::BrowserBridgeChild(nsFrameLoader* aFrameLoader,
+                                       BrowsingContext* aBrowsingContext)
+    : mLayersId{0},
+      mIPCOpen(true),
+      mFrameLoader(aFrameLoader),
+      mBrowsingContext(aBrowsingContext) {}
 
 BrowserBridgeChild::~BrowserBridgeChild() {}
 
 already_AddRefed<BrowserBridgeChild> BrowserBridgeChild::Create(
     nsFrameLoader* aFrameLoader, const TabContext& aContext,
-    const nsString& aRemoteType) {
+    const nsString& aRemoteType, BrowsingContext* aBrowsingContext) {
   MOZ_ASSERT(XRE_IsContentProcess());
 
   // Determine our embedder's TabChild actor.
   RefPtr<Element> owner = aFrameLoader->GetOwnerContent();
   MOZ_DIAGNOSTIC_ASSERT(owner);
 
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(owner->GetOwnerGlobal());
   MOZ_DIAGNOSTIC_ASSERT(docShell);
 
   RefPtr<TabChild> tabChild = TabChild::GetFrom(docShell);
   MOZ_DIAGNOSTIC_ASSERT(tabChild);
 
   RefPtr<BrowserBridgeChild> browserBridge =
-      new BrowserBridgeChild(aFrameLoader);
+      new BrowserBridgeChild(aFrameLoader, aBrowsingContext);
   // Reference is freed in TabChild::DeallocPBrowserBridgeChild.
   tabChild->SendPBrowserBridgeConstructor(
       do_AddRef(browserBridge).take(),
-      PromiseFlatString(aContext.PresentationURL()), aRemoteType);
+      PromiseFlatString(aContext.PresentationURL()), aRemoteType,
+      aBrowsingContext);
   browserBridge->mIPCOpen = true;
 
   return browserBridge.forget();
 }
 
 void BrowserBridgeChild::UpdateDimensions(const nsIntRect& aRect,
                                           const mozilla::ScreenIntSize& aSize) {
   MOZ_DIAGNOSTIC_ASSERT(mIPCOpen);
--- a/dom/ipc/BrowserBridgeChild.h
+++ b/dom/ipc/BrowserBridgeChild.h
@@ -7,34 +7,40 @@
 #ifndef mozilla_dom_BrowserBridgeChild_h
 #define mozilla_dom_BrowserBridgeChild_h
 
 #include "mozilla/dom/PBrowserBridgeChild.h"
 #include "mozilla/dom/TabChild.h"
 
 namespace mozilla {
 namespace dom {
+class BrowsingContext;
 
 /**
  * Child side for a remote frame.
  */
 class BrowserBridgeChild : public PBrowserBridgeChild {
  public:
   NS_INLINE_DECL_REFCOUNTING(BrowserBridgeChild);
 
   TabChild* Manager() {
     MOZ_ASSERT(mIPCOpen);
     return static_cast<TabChild*>(PBrowserBridgeChild::Manager());
   }
 
   mozilla::layers::LayersId GetLayersId() { return mLayersId; }
 
+  BrowsingContext* GetBrowsingContext() { return mBrowsingContext; }
+
+  // XXX(nika): We should have a load context here. (bug 1532664)
+  nsILoadContext* GetLoadContext() { return nullptr; }
+
   static already_AddRefed<BrowserBridgeChild> Create(
       nsFrameLoader* aFrameLoader, const TabContext& aContext,
-      const nsString& aRemoteType);
+      const nsString& aRemoteType, BrowsingContext* aBrowsingContext);
 
   void UpdateDimensions(const nsIntRect& aRect,
                         const mozilla::ScreenIntSize& aSize);
 
   void NavigateByKey(bool aForward, bool aForDocumentNavigation);
 
   void Activate();
 
@@ -53,20 +59,22 @@ class BrowserBridgeChild : public PBrows
   mozilla::ipc::IPCResult RecvRequestFocus(const bool& aCanRaise);
 
   mozilla::ipc::IPCResult RecvMoveFocus(const bool& aForward,
                                         const bool& aForDocumentNavigation);
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
-  explicit BrowserBridgeChild(nsFrameLoader* aFrameLoader);
+  explicit BrowserBridgeChild(nsFrameLoader* aFrameLoader,
+                              BrowsingContext* aBrowsingContext);
   ~BrowserBridgeChild();
 
   mozilla::layers::LayersId mLayersId;
   bool mIPCOpen;
   RefPtr<nsFrameLoader> mFrameLoader;
+  RefPtr<BrowsingContext> mBrowsingContext;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // !defined(mozilla_dom_BrowserBridgeParent_h)
--- a/dom/ipc/BrowserBridgeParent.cpp
+++ b/dom/ipc/BrowserBridgeParent.cpp
@@ -2,16 +2,18 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/BrowserBridgeParent.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentProcessManager.h"
+#include "mozilla/dom/CanonicalBrowsingContext.h"
+#include "mozilla/dom/BrowsingContextGroup.h"
 
 using namespace mozilla::ipc;
 using namespace mozilla::layout;
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace dom {
 
@@ -19,17 +21,18 @@ BrowserBridgeParent::BrowserBridgeParent
 
 BrowserBridgeParent::~BrowserBridgeParent() {
   if (mTabParent) {
     mTabParent->mBrowserBridgeParent = nullptr;
   }
 }
 
 nsresult BrowserBridgeParent::Init(const nsString& aPresentationURL,
-                                   const nsString& aRemoteType) {
+                                   const nsString& aRemoteType,
+                                   CanonicalBrowsingContext* aBrowsingContext) {
   mIPCOpen = true;
 
   // FIXME: This should actually use a non-bogus TabContext, probably inherited
   // from our Manager().
   OriginAttributes attrs;
   attrs.mInIsolatedMozBrowser = false;
   attrs.mAppId = nsIScriptSecurityManager::NO_APP_ID;
   attrs.SyncAttributesWithPrivateBrowsing(false);
@@ -43,31 +46,37 @@ nsresult BrowserBridgeParent::Init(const
   RefPtr<ContentParent> constructorSender =
       ContentParent::GetNewOrUsedBrowserProcess(
           nullptr, aRemoteType, initialPriority, nullptr, false);
   if (NS_WARN_IF(!constructorSender)) {
     MOZ_ASSERT(false, "Unable to allocate content process!");
     return NS_ERROR_FAILURE;
   }
 
+  // Ensure that our content process is subscribed to our newly created
+  // BrowsingContextGroup.
+  aBrowsingContext->Group()->EnsureSubscribed(constructorSender);
+  aBrowsingContext->SetOwnerProcessId(constructorSender->ChildID());
+
   ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   TabId tabId(nsContentUtils::GenerateTabId());
   cpm->RegisterRemoteFrame(tabId, ContentParentId(0), TabId(0),
                            tabContext.AsIPCTabContext(),
                            constructorSender->ChildID());
 
   // Construct the TabParent object for our subframe.
   uint32_t chromeFlags = 0;
-  RefPtr<TabParent> tabParent(
-      new TabParent(constructorSender, tabId, tabContext, chromeFlags, this));
+  RefPtr<TabParent> tabParent(new TabParent(constructorSender, tabId,
+                                            tabContext, aBrowsingContext,
+                                            chromeFlags, this));
 
   PBrowserParent* browser = constructorSender->SendPBrowserConstructor(
       // DeallocPBrowserParent() releases this ref.
       tabParent.forget().take(), tabId, TabId(0), tabContext.AsIPCTabContext(),
-      chromeFlags, constructorSender->ChildID(),
+      chromeFlags, constructorSender->ChildID(), aBrowsingContext,
       constructorSender->IsForBrowser());
   if (NS_WARN_IF(!browser)) {
     MOZ_ASSERT(false, "Browser Constructor Failed");
     return NS_ERROR_FAILURE;
   }
 
   // Set our TabParent object to the newly created browser.
   mTabParent = TabParent::GetFrom(browser);
--- a/dom/ipc/BrowserBridgeParent.h
+++ b/dom/ipc/BrowserBridgeParent.h
@@ -15,20 +15,25 @@ namespace dom {
 
 class BrowserBridgeParent : public PBrowserBridgeParent {
  public:
   NS_INLINE_DECL_REFCOUNTING(BrowserBridgeParent);
 
   BrowserBridgeParent();
 
   // Initialize this actor after performing startup.
-  nsresult Init(const nsString& aPresentationURL, const nsString& aRemoteType);
+  nsresult Init(const nsString& aPresentationURL, const nsString& aRemoteType,
+                CanonicalBrowsingContext* aBrowsingContext);
 
   TabParent* GetTabParent() { return mTabParent; }
 
+  CanonicalBrowsingContext* GetBrowsingContext() {
+    return mTabParent->GetBrowsingContext();
+  }
+
   // Get our manager actor.
   TabParent* Manager() {
     MOZ_ASSERT(mIPCOpen);
     return static_cast<TabParent*>(PBrowserBridgeParent::Manager());
   }
 
  protected:
   friend class PBrowserBridgeParent;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -23,16 +23,18 @@
 #include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/RemoteDecoderManagerChild.h"
 #include "mozilla/Unused.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/TelemetryIPC.h"
 #include "mozilla/VideoDecoderManagerChild.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
+#include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/BrowsingContextGroup.h"
 #include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientOpenWindowOpActors.h"
 #include "mozilla/dom/ChildProcessMessageManager.h"
 #include "mozilla/dom/ContentProcessMessageManager.h"
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DocGroup.h"
@@ -907,33 +909,39 @@ nsresult ContentChild::ProvideWindowComm
   RefPtr<TabGroup> tabGroup;
   if (aTabOpener && !aForceNoOpener) {
     // The new actor will use the same tab group as the opener.
     tabGroup = aTabOpener->TabGroup();
   } else {
     tabGroup = new TabGroup();
   }
 
+  RefPtr<BrowsingContext> openerBC =
+      aParent ? nsPIDOMWindowOuter::From(aParent)->GetBrowsingContext()
+              : nullptr;
+  RefPtr<BrowsingContext> browsingContext = BrowsingContext::Create(
+      nullptr, openerBC, aName, BrowsingContext::Type::Content);
+
   TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
-  RefPtr<TabChild> newChild =
-      new TabChild(this, tabId, tabGroup, newTabContext, aChromeFlags);
+  RefPtr<TabChild> newChild = new TabChild(this, tabId, tabGroup, newTabContext,
+                                           browsingContext, aChromeFlags);
 
   if (aTabOpener) {
     MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
     ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
   }
 
   nsCOMPtr<nsIEventTarget> target =
       tabGroup->EventTargetFor(TaskCategory::Other);
   SetEventTargetForActor(newChild, target);
 
   Unused << SendPBrowserConstructor(
       // We release this ref in DeallocPBrowserChild
       RefPtr<TabChild>(newChild).forget().take(), tabId, TabId(0), *ipcContext,
-      aChromeFlags, GetID(), IsForBrowser());
+      aChromeFlags, GetID(), browsingContext, IsForBrowser());
 
   // Now that |newChild| has had its IPC link established, call |Init| to set it
   // up.
   if (NS_FAILED(newChild->Init(aParent))) {
     return NS_ERROR_ABORT;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> parentTopInnerWindow;
@@ -1692,60 +1700,61 @@ mozilla::jsipc::PJavaScriptChild* Conten
   return NewJavaScriptChild();
 }
 
 bool ContentChild::DeallocPJavaScriptChild(PJavaScriptChild* aChild) {
   ReleaseJavaScriptChild(aChild);
   return true;
 }
 
-PBrowserChild* ContentChild::AllocPBrowserChild(const TabId& aTabId,
-                                                const TabId& aSameTabGroupAs,
-                                                const IPCTabContext& aContext,
-                                                const uint32_t& aChromeFlags,
-                                                const ContentParentId& aCpID,
-                                                const bool& aIsForBrowser) {
+PBrowserChild* ContentChild::AllocPBrowserChild(
+    const TabId& aTabId, const TabId& aSameTabGroupAs,
+    const IPCTabContext& aContext, const uint32_t& aChromeFlags,
+    const ContentParentId& aCpID, BrowsingContext* aBrowsingContext,
+    const bool& aIsForBrowser) {
   // We'll happily accept any kind of IPCTabContext here; we don't need to
   // check that it's of a certain type for security purposes, because we
   // believe whatever the parent process tells us.
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
                              "the parent process. (%s)  Crashing...",
                              tc.GetInvalidReason())
                  .get());
     MOZ_CRASH("Invalid TabContext received from the parent process.");
   }
 
-  RefPtr<TabChild> child =
-      TabChild::Create(static_cast<ContentChild*>(this), aTabId,
-                       aSameTabGroupAs, tc.GetTabContext(), aChromeFlags);
+  RefPtr<TabChild> child = TabChild::Create(
+      static_cast<ContentChild*>(this), aTabId, aSameTabGroupAs,
+      tc.GetTabContext(), aBrowsingContext, aChromeFlags);
 
   // The ref here is released in DeallocPBrowserChild.
   return child.forget().take();
 }
 
 bool ContentChild::SendPBrowserConstructor(
     PBrowserChild* aActor, const TabId& aTabId, const TabId& aSameTabGroupAs,
     const IPCTabContext& aContext, const uint32_t& aChromeFlags,
-    const ContentParentId& aCpID, const bool& aIsForBrowser) {
+    const ContentParentId& aCpID, BrowsingContext* aBrowsingContext,
+    const bool& aIsForBrowser) {
   if (IsShuttingDown()) {
     return false;
   }
 
   return PContentChild::SendPBrowserConstructor(aActor, aTabId, aSameTabGroupAs,
                                                 aContext, aChromeFlags, aCpID,
-                                                aIsForBrowser);
+                                                aBrowsingContext, aIsForBrowser);
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvPBrowserConstructor(
     PBrowserChild* aActor, const TabId& aTabId, const TabId& aSameTabGroupAs,
     const IPCTabContext& aContext, const uint32_t& aChromeFlags,
-    const ContentParentId& aCpID, const bool& aIsForBrowser) {
+    const ContentParentId& aCpID, BrowsingContext* aBrowsingContext,
+    const bool& aIsForBrowser) {
   MOZ_ASSERT(!IsShuttingDown());
 
   static bool hasRunOnce = false;
   if (!hasRunOnce) {
     hasRunOnce = true;
     MOZ_ASSERT(!gFirstIdleTask);
     RefPtr<CancelableRunnable> firstIdleTask =
         NewCancelableRunnableFunction("FirstIdleRunnable", FirstIdle);
@@ -3674,16 +3683,70 @@ PContentChild::Result ContentChild::OnMe
     MOZ_ASSERT(!aMsg.is_reply());
 
     LSObject::OnSyncMessageHandled();
   }
 
   return result;
 }
 
+mozilla::ipc::IPCResult ContentChild::RecvAttachBrowsingContext(
+    BrowsingContext::IPCInitializer&& aInit) {
+  RefPtr<BrowsingContext> child = BrowsingContext::Get(aInit.mId);
+  MOZ_RELEASE_ASSERT(!child || child->IsCached());
+
+  if (!child) {
+    // Determine the BrowsingContextGroup from our parent or opener fields.
+    RefPtr<BrowsingContextGroup> group =
+        BrowsingContextGroup::Select(aInit.mParentId, aInit.mOpenerId);
+    child = BrowsingContext::CreateFromIPC(std::move(aInit), group, nullptr);
+  }
+
+  child->Attach(/* aFromIPC */ true);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult ContentChild::RecvDetachBrowsingContext(
+    BrowsingContext* aContext, bool aMoveToBFCache) {
+  MOZ_RELEASE_ASSERT(aContext);
+
+  if (aMoveToBFCache) {
+    aContext->CacheChildren(/* aFromIPC */ true);
+  } else {
+    aContext->Detach(/* aFromIPC */ true);
+  }
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult ContentChild::RecvRegisterBrowsingContextGroup(
+    nsTArray<BrowsingContext::IPCInitializer>&& aInits) {
+  RefPtr<BrowsingContextGroup> group = new BrowsingContextGroup();
+
+  // Each of the initializers in aInits is sorted in pre-order, so our parent
+  // should always be available before the element itself.
+  for (auto& init : aInits) {
+#ifdef DEBUG
+    RefPtr<BrowsingContext> existing = BrowsingContext::Get(init.mId);
+    MOZ_ASSERT(!existing, "BrowsingContext must not exist yet!");
+
+    RefPtr<BrowsingContext> parent = init.GetParent();
+    MOZ_ASSERT_IF(parent, parent->Group() == group);
+#endif
+
+    RefPtr<BrowsingContext> ctxt = BrowsingContext::CreateFromIPC(std::move(init), group, nullptr);
+
+    // FIXME: We should deal with cached & detached contexts as well.
+    ctxt->Attach(/* aFromIPC */ true);
+  }
+
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult ContentChild::RecvWindowClose(BrowsingContext* aContext,
                                                       bool aTrustedCaller) {
   if (!aContext) {
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
             ("ChildIPC: Trying to send a message to dead or detached context"));
     return IPC_OK();
   }
 
@@ -3753,17 +3816,17 @@ mozilla::ipc::IPCResult ContentChild::Re
 
   window->Dispatch(TaskCategory::Other, event.forget());
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvCommitBrowsingContextTransaction(
     BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction) {
   if (aContext) {
-    aTransaction.Apply(aContext);
+    aTransaction.Apply(aContext, nullptr);
   }
   return IPC_OK();
 }
 
 }  // namespace dom
 
 #if defined(__OpenBSD__) && defined(MOZ_CONTENT_SANDBOX)
 #  include <unistd.h>
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -193,16 +193,17 @@ class ContentChild final : public PConte
   mozilla::ipc::IPCResult RecvSetProcessSandbox(
       const Maybe<FileDescriptor>& aBroker);
 
   PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
                                     const TabId& aSameTabGroupAs,
                                     const IPCTabContext& aContext,
                                     const uint32_t& aChromeFlags,
                                     const ContentParentId& aCpID,
+                                    BrowsingContext* aBrowsingContext,
                                     const bool& aIsForBrowser);
 
   bool DeallocPBrowserChild(PBrowserChild*);
 
   PIPCBlobInputStreamChild* AllocPIPCBlobInputStreamChild(
       const nsID& aID, const uint64_t& aSize);
 
   bool DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor);
@@ -510,22 +511,24 @@ class ContentChild final : public PConte
 
   bool DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*);
 
   bool SendPBrowserConstructor(PBrowserChild* actor, const TabId& aTabId,
                                const TabId& aSameTabGroupAs,
                                const IPCTabContext& context,
                                const uint32_t& chromeFlags,
                                const ContentParentId& aCpID,
+                               BrowsingContext* aBrowsingContext,
                                const bool& aIsForBrowser);
 
   virtual mozilla::ipc::IPCResult RecvPBrowserConstructor(
       PBrowserChild* aCctor, const TabId& aTabId, const TabId& aSameTabGroupAs,
       const IPCTabContext& aContext, const uint32_t& aChromeFlags,
-      const ContentParentId& aCpID, const bool& aIsForBrowser) override;
+      const ContentParentId& aCpID, BrowsingContext* aBrowsingContext,
+      const bool& aIsForBrowser) override;
 
   FORWARD_SHMEM_ALLOCATOR_TO(PContentChild)
 
   void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
 
   PBrowserOrId GetBrowserOrId(TabChild* aTabChild);
 
   POfflineCacheUpdateChild* AllocPOfflineCacheUpdateChild(
@@ -705,16 +708,25 @@ class ContentChild final : public PConte
   virtual already_AddRefed<nsIEventTarget> GetConstructedEventTarget(
       const Message& aMsg) override;
 
   virtual already_AddRefed<nsIEventTarget> GetSpecificMessageEventTarget(
       const Message& aMsg) override;
 
   virtual void OnChannelReceivedMessage(const Message& aMsg) override;
 
+  mozilla::ipc::IPCResult RecvAttachBrowsingContext(
+      BrowsingContext::IPCInitializer&& aInit);
+
+  mozilla::ipc::IPCResult RecvDetachBrowsingContext(BrowsingContext* aContext,
+                                                    bool aMoveToBFCache);
+
+  mozilla::ipc::IPCResult RecvRegisterBrowsingContextGroup(
+      nsTArray<BrowsingContext::IPCInitializer>&& aInits);
+
   mozilla::ipc::IPCResult RecvWindowClose(BrowsingContext* aContext,
                                           bool aTrustedCaller);
   mozilla::ipc::IPCResult RecvWindowFocus(BrowsingContext* aContext);
   mozilla::ipc::IPCResult RecvWindowBlur(BrowsingContext* aContext);
   mozilla::ipc::IPCResult RecvWindowPostMessage(
       BrowsingContext* aContext, const ClonedMessageData& aMessage,
       const PostMessageData& aData);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1137,16 +1137,28 @@ TabParent* ContentParent::CreateBrowser(
       constructorSender =
           GetNewOrUsedBrowserProcess(aFrameElement, remoteType, initialPriority,
                                      nullptr, isPreloadBrowser);
     }
     if (!constructorSender) {
       return nullptr;
     }
   }
+
+  // FIXME: This BrowsingContext should be provided by the nsFrameLoader.
+  // (bug 1523636)
+  RefPtr<CanonicalBrowsingContext> browsingContext =
+      BrowsingContext::Create(nullptr, nullptr, EmptyString(),
+                              BrowsingContext::Type::Content)
+          .downcast<CanonicalBrowsingContext>();
+
+  // Ensure that our content process is subscribed to our newly created
+  // BrowsingContextGroup.
+  browsingContext->Group()->EnsureSubscribed(constructorSender);
+
   ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   cpm->RegisterRemoteFrame(tabId, ContentParentId(0), openerTabId,
                            aContext.AsIPCTabContext(),
                            constructorSender->ChildID());
 
   if (constructorSender) {
     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     docShell->GetTreeOwner(getter_AddRefs(treeOwner));
@@ -1167,25 +1179,27 @@ TabParent* ContentParent::CreateBrowser(
     }
     if (docShell->GetAffectPrivateSessionLifetime()) {
       chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
     }
 
     if (tabId == 0) {
       return nullptr;
     }
-    RefPtr<TabParent> tp(
-        new TabParent(constructorSender, tabId, aContext, chromeFlags));
+    RefPtr<TabParent> tp = new TabParent(constructorSender, tabId, aContext,
+                                         browsingContext, chromeFlags);
+
+    browsingContext->SetOwnerProcessId(constructorSender->ChildID());
 
     PBrowserParent* browser = constructorSender->SendPBrowserConstructor(
         // DeallocPBrowserParent() releases this ref.
         tp.forget().take(), tabId,
         aSameTabGroupAs ? aSameTabGroupAs->GetTabId() : TabId(0),
         aContext.AsIPCTabContext(), chromeFlags, constructorSender->ChildID(),
-        constructorSender->IsForBrowser());
+        browsingContext, constructorSender->IsForBrowser());
 
     if (remoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
       // Tell the TabChild object that it was created due to a Large-Allocation
       // request.
       Unused << browser->SendAwaitLargeAlloc();
     }
 
     if (browser) {
@@ -3218,17 +3232,18 @@ bool ContentParent::CanOpenBrowser(const
   }
 
   return true;
 }
 
 PBrowserParent* ContentParent::AllocPBrowserParent(
     const TabId& aTabId, const TabId& aSameTabGroupAs,
     const IPCTabContext& aContext, const uint32_t& aChromeFlags,
-    const ContentParentId& aCpId, const bool& aIsForBrowser) {
+    const ContentParentId& aCpId, BrowsingContext* aBrowsingContext,
+    const bool& aIsForBrowser) {
   MOZ_ASSERT(!aSameTabGroupAs);
 
   Unused << aCpId;
   Unused << aIsForBrowser;
 
   if (!CanOpenBrowser(aContext)) {
     return nullptr;
   }
@@ -3276,36 +3291,44 @@ PBrowserParent* ContentParent::AllocPBro
       return nullptr;
     }
   }
 
   // And because we're allocating a remote browser, of course the
   // window is remote.
   chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
 
+  CanonicalBrowsingContext* browsingContext =
+      CanonicalBrowsingContext::Cast(aBrowsingContext);
+  if (NS_WARN_IF(!browsingContext->IsOwnedByProcess(ChildID()))) {
+    MOZ_ASSERT(false, "BrowsingContext not owned by the correct process!");
+    return nullptr;
+  }
+
   MaybeInvalidTabContext tc(aContext);
   MOZ_ASSERT(tc.IsValid());
-  TabParent* parent = new TabParent(static_cast<ContentParent*>(this), aTabId,
-                                    tc.GetTabContext(), chromeFlags);
+  TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(),
+                                    browsingContext, chromeFlags);
 
   // We release this ref in DeallocPBrowserParent()
   NS_ADDREF(parent);
   return parent;
 }
 
 bool ContentParent::DeallocPBrowserParent(PBrowserParent* frame) {
   TabParent* parent = TabParent::GetFrom(frame);
   NS_RELEASE(parent);
   return true;
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvPBrowserConstructor(
     PBrowserParent* actor, const TabId& tabId, const TabId& sameTabGroupAs,
     const IPCTabContext& context, const uint32_t& chromeFlags,
-    const ContentParentId& cpId, const bool& isForBrowser) {
+    const ContentParentId& cpId, BrowsingContext* aBrowsingContext,
+    const bool& isForBrowser) {
   TabParent* parent = TabParent::GetFrom(actor);
   // When enabling input event prioritization, input events may preempt other
   // normal priority IPC messages. To prevent the input events preempt
   // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
   // notify parent that TabChild is created. In this case, PBrowser is initiated
   // from content so that we can set TabParent as ready to handle input events.
   parent->SetReadyToHandleInputEvents();
   return IPC_OK();
@@ -5667,56 +5690,64 @@ ContentParent::RecvFirstPartyStorageAcce
 
 mozilla::ipc::IPCResult ContentParent::RecvStoreUserInteractionAsPermission(
     const Principal& aPrincipal) {
   AntiTrackingCommon::StoreUserInteractionFor(aPrincipal);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvAttachBrowsingContext(
-    BrowsingContext* aParent, BrowsingContext* aOpener,
-    BrowsingContextId aChildId, const nsString& aName) {
-  if (aParent && !aParent->Canonical()->IsOwnedByProcess(ChildID())) {
+    BrowsingContext::IPCInitializer&& aInit) {
+  RefPtr<CanonicalBrowsingContext> parent;
+  if (aInit.mParentId != 0) {
+    parent = CanonicalBrowsingContext::Get(aInit.mParentId);
+    MOZ_RELEASE_ASSERT(parent, "Parent doesn't exist in parent process");
+  }
+
+  if (parent && !parent->IsOwnedByProcess(ChildID())) {
     // Where trying attach a child BrowsingContext to a parent
     // BrowsingContext in another process. This is illegal since the
     // only thing that could create that child BrowsingContext is a
     // parent docshell in the same process as that BrowsingContext.
 
     // TODO(farre): We're doing nothing now, but is that exactly what
     // we want? Maybe we want to crash the child currently calling
     // SendAttachBrowsingContext and/or the child that originally
     // called SendAttachBrowsingContext or possibly all children that
     // has a BrowsingContext connected to the child that currently
     // called SendAttachBrowsingContext? [Bug 1471598]
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
             ("ParentIPC: Trying to attach to out of process parent context "
              "0x%08" PRIx64,
-             aParent->Id()));
+             aInit.mParentId));
     return IPC_OK();
   }
 
-  RefPtr<BrowsingContext> child = BrowsingContext::Get(aChildId);
+  RefPtr<BrowsingContext> child = BrowsingContext::Get(aInit.mId);
   if (child && !child->IsCached()) {
     // This is highly suspicious. BrowsingContexts should only be
     // attached at most once, but finding one indicates that someone
     // is doing something they shouldn't.
 
     // TODO(farre): To crash or not to crash. Same reasoning as in
     // above TODO. [Bug 1471598]
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
             ("ParentIPC: Trying to attach already attached 0x%08" PRIx64
              " to 0x%08" PRIx64,
-             child->Id(), aParent ? aParent->Id() : 0));
+             aInit.mId, aInit.mParentId));
     return IPC_OK();
   }
 
   if (!child) {
-    child = BrowsingContext::CreateFromIPC(aParent, aOpener, aName,
-                                           (uint64_t)aChildId, this);
-  }
+    RefPtr<BrowsingContextGroup> group =
+      BrowsingContextGroup::Select(aInit.mParentId, aInit.mOpenerId);
+    child = BrowsingContext::CreateFromIPC(std::move(aInit), group, this);
+  }
+
+  child->Attach(/* aFromIPC */ true);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvDetachBrowsingContext(
     BrowsingContext* aContext, bool aMoveToBFCache) {
   if (!aContext) {
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
@@ -5734,61 +5765,21 @@ mozilla::ipc::IPCResult ContentParent::R
     // above TODO. [Bug 1471598]
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
             ("ParentIPC: Trying to detach out of process context 0x%08" PRIx64,
              aContext->Id()));
     return IPC_OK();
   }
 
   if (aMoveToBFCache) {
-    aContext->CacheChildren();
+    aContext->CacheChildren(/* aFromIPC */ true);
   } else {
-    aContext->Detach();
-  }
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult ContentParent::RecvSetOpenerBrowsingContext(
-    BrowsingContext* aContext, BrowsingContext* aOpener) {
-  if (!aContext) {
-    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
-            ("ParentIPC: Trying to set opener already detached"));
-    return IPC_OK();
-  }
-
-  if (!aContext->Canonical()->IsOwnedByProcess(ChildID())) {
-    // Where trying to set opener on a child BrowsingContext in
-    // another child process. This is illegal since the owner of the
-    // BrowsingContext is the proccess with the in-process docshell,
-    // which is tracked by OwnerProcessId.
-
-    // TODO(farre): To crash or not to crash. Same reasoning as in
-    // above TODO. [Bug 1471598]
-    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
-            ("ParentIPC: Trying to set opener on out of process context "
-             "0x%08" PRIx64,
-             aContext->Id()));
-    return IPC_OK();
-  }
-
-  aContext->SetOpener(aOpener);
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult ContentParent::RecvSetUserGestureActivation(
-    BrowsingContext* aContext, bool aNewValue) {
-  if (!aContext) {
-    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
-            ("ParentIPC: Trying to activate wrong context"));
-    return IPC_OK();
-  }
-
-  aContext->Canonical()->NotifySetUserGestureActivationFromIPC(aNewValue);
+    aContext->Detach(/* aFromIPC */ true);
+  }
+
   return IPC_OK();
 }
 
 void ContentParent::RegisterRemoteWorkerActor() { ++mRemoteWorkerActors; }
 
 void ContentParent::UnregisterRemoveWorkerActor() {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -5898,27 +5889,34 @@ void ContentParent::OnBrowsingContextGro
 mozilla::ipc::IPCResult ContentParent::RecvCommitBrowsingContextTransaction(
     BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction) {
   if (!aContext) {
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
             ("ParentIPC: Trying to run transaction on missing context."));
     return IPC_OK();
   }
 
+  // Check if the transaction is valid.
+  if (!aContext->Canonical()->ValidateTransaction(aTransaction, this)) {
+    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Error,
+            ("ParentIPC: Trying to run invalid transaction."));
+    return IPC_FAIL_NO_REASON(this);
+  }
+
   for (auto iter = aContext->Group()->ContentParentsIter(); !iter.Done();
        iter.Next()) {
     auto* entry = iter.Get();
     ContentParent* parent = entry->GetKey();
     if (parent != this) {
       Unused << parent->SendCommitBrowsingContextTransaction(aContext,
                                                              aTransaction);
     }
   }
 
-  aTransaction.Apply(aContext);
+  aTransaction.Apply(aContext, this);
 
   return IPC_OK();
 }
 }  // namespace dom
 }  // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -605,36 +605,29 @@ class ContentParent final : public PCont
 
   // Control the priority of the IPC messages for input events.
   void SetInputPriorityEventEnabled(bool aEnabled);
   bool IsInputPriorityEventEnabled() { return mIsInputPriorityEventEnabled; }
 
   static bool IsInputEventQueueSupported();
 
   mozilla::ipc::IPCResult RecvAttachBrowsingContext(
-      BrowsingContext* aParentContext, BrowsingContext* aOpener,
-      BrowsingContextId aContextId, const nsString& aName);
+      BrowsingContext::IPCInitializer&& aInit);
 
   mozilla::ipc::IPCResult RecvDetachBrowsingContext(BrowsingContext* aContext,
                                                     bool aMoveToBFCache);
 
-  mozilla::ipc::IPCResult RecvSetOpenerBrowsingContext(
-      BrowsingContext* aContext, BrowsingContext* aOpener);
-
   mozilla::ipc::IPCResult RecvWindowClose(BrowsingContext* aContext,
                                           bool aTrustedCaller);
   mozilla::ipc::IPCResult RecvWindowFocus(BrowsingContext* aContext);
   mozilla::ipc::IPCResult RecvWindowBlur(BrowsingContext* aContext);
   mozilla::ipc::IPCResult RecvWindowPostMessage(
       BrowsingContext* aContext, const ClonedMessageData& aMessage,
       const PostMessageData& aData);
 
-  mozilla::ipc::IPCResult RecvSetUserGestureActivation(
-      BrowsingContext* aContext, bool aNewValue);
-
   FORWARD_SHMEM_ALLOCATOR_TO(PContentParent)
 
  protected:
   void OnChannelConnected(int32_t pid) override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   bool ShouldContinueFromReplyTimeout() override;
@@ -817,24 +810,26 @@ class ContentParent final : public PCont
 
   bool DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*);
 
   PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
                                       const TabId& aSameTabGroupAs,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
                                       const ContentParentId& aCpId,
+                                      BrowsingContext* aBrowsingContext,
                                       const bool& aIsForBrowser);
 
   bool DeallocPBrowserParent(PBrowserParent* frame);
 
   virtual mozilla::ipc::IPCResult RecvPBrowserConstructor(
       PBrowserParent* actor, const TabId& tabId, const TabId& sameTabGroupAs,
       const IPCTabContext& context, const uint32_t& chromeFlags,
-      const ContentParentId& cpId, const bool& isForBrowser) override;
+      const ContentParentId& cpId, BrowsingContext* aBrowsingContext,
+      const bool& isForBrowser) override;
 
   PIPCBlobInputStreamParent* AllocPIPCBlobInputStreamParent(
       const nsID& aID, const uint64_t& aSize);
 
   bool DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor);
 
   mozilla::ipc::IPCResult RecvIsSecureURI(
       const uint32_t& aType, const URIParams& aURI, const uint32_t& aFlags,
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -173,17 +173,18 @@ parent:
      * Construct a new WindowGlobal actor for a window global in the given
      * BrowsingContext and with the given principal.
      */
     async PWindowGlobal(WindowGlobalInit init);
 
     /**
      * Construct a new Remote iframe actor.
      */
-    async PBrowserBridge(nsString aPresentationURL, nsString aRemoteType);
+    async PBrowserBridge(nsString aPresentationURL, nsString aRemoteType,
+                         BrowsingContext aBrowsingContext);
 
     /**
      * Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
      * widget's shareable window on the chrome side. Only used on Windows.
      */
     async SetNativeChildOfShareableWindow(uintptr_t childWindow);
 
     /**
@@ -615,18 +616,16 @@ parent:
                                      bool aHideDoorHanger);
 
     sync SetSystemFont(nsCString aFontName);
     sync GetSystemFont() returns (nsCString retval);
 
     sync SetPrefersReducedMotionOverrideForTest(bool aValue);
     sync ResetPrefersReducedMotionOverrideForTest();
 
-    async RootBrowsingContext(BrowsingContext aContext);
-
 child:
     /**
      * Notify the remote browser that it has been Show()n on this
      * side, with the given |visibleRect|.  This message is expected
      * to trigger creation of the remote browser's "widget".
      *
      * |Show()| and |Move()| take IntSizes rather than Rects because
      * content processes always render to a virtual <0, 0> top-left
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -94,16 +94,17 @@ using mozilla::Telemetry::KeyedScalarAct
 using mozilla::Telemetry::DynamicScalarDefinition from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::ChildEventData from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::DiscardedData from "mozilla/TelemetryComms.h";
 using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
 using refcounted class nsIInputStream from "mozilla/ipc/IPCStreamUtils.h";
 using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
 using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::BrowsingContextTransaction from "mozilla/dom/BrowsingContext.h";
+using mozilla::dom::BrowsingContextInitializer from "mozilla/dom/BrowsingContext.h";
 
 union ChromeRegistryItem
 {
     ChromePackage;
     OverrideMapping;
     SubstitutionMapping;
 };
 
@@ -384,17 +385,18 @@ both:
     //
     // If |sameTabGroupAs| is non-zero, the new tab should go in the same
     // TabGroup as |sameTabGroupAs|. This parameter should always be zero
     // for PBrowser messages sent from the child to the parent.
     //
     // Keep the last 3 attributes in sync with GetProcessAttributes!
     async PBrowser(TabId tabId, TabId sameTabGroupAs,
                    IPCTabContext context, uint32_t chromeFlags,
-                   ContentParentId cpId, bool isForBrowser);
+                   ContentParentId cpId, BrowsingContext browsingContext,
+                   bool isForBrowser);
 
     async PFileDescriptorSet(FileDescriptor fd);
 
     // For parent->child, aBrowser must be non-null; aOuterWindowID can
     // be 0 to indicate the browser's current root document, or nonzero
     // to persist a subdocument.  For child->parent, arguments are
     // ignored and should be null/zero.
     async PWebBrowserPersistDocument(nullable PBrowser aBrowser,
@@ -770,16 +772,20 @@ child:
     async CrossProcessRedirect(uint32_t aRegistrarId,
                                nsIURI aURI,
                                uint32_t aNewLoadFlags,
                                LoadInfoArgs? aLoadInfo,
                                uint64_t aChannelId,
                                nsIURI aOriginalURI,
                                uint64_t aIdentifier);
 
+    // Begin subscribing to a new BrowsingContextGroup, sending down the current
+    // value for every individual BrowsingContext.
+    async RegisterBrowsingContextGroup(BrowsingContextInitializer[] aInits);
+
 parent:
     async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
 
     sync OpenRecordReplayChannel(uint32_t channelId)
         returns (FileDescriptor connection);
     async CreateReplayingProcess(uint32_t channelId);
 
     async CreateGMPService();
@@ -1218,57 +1224,16 @@ parent:
                                                   Principal aTrackingPrincipal,
                                                   nsCString aTrackingOrigin,
                                                   nsCString aGrantedOrigin,
                                                   int aAllowMode)
           returns (bool unused);
 
     async StoreUserInteractionAsPermission(Principal aPrincipal);
 
-    /**
-     * Sync the BrowsingContext with id 'aContextId' and name 'aName' to the
-     * parent, and attach it to the BrowsingContext 'aParentContext'. If
-     * 'aParentContext' is 'nullptr' the BrowsingContext is a root in the
-     * BrowsingContext tree. AttachBrowsingContext must only be called at most
-     * once for any child BrowsingContext, and only for BrowsingContexts where
-     * the parent and the child context contains their nsDocShell.
-     */
-    async AttachBrowsingContext(BrowsingContext aParentContext,
-                                BrowsingContext aOpener,
-                                BrowsingContextId aContextId,
-                                nsString aName);
-
-    /**
-     * Remove the synced BrowsingContext 'aContext' from the parent.
-     * DetachBrowsingContext is only needed to be called once for any
-     * BrowsingContext, since detaching a node in the BrowsingContext detaches
-     * the entire sub-tree rooted at that node. Calling DetachBrowsingContext
-     * with an already detached BrowsingContext effectively does nothing. Note
-     * that it is not an error to call DetachBrowsingContext on a
-     * BrowsingContext belonging to an already detached subtree. The
-     * 'aMoveToBFCache' paramater controls if detaching a BrowsingContext
-     * should move it to the bfcache allowing it to be re-attached if navigated
-     * to.
-     */
-    async DetachBrowsingContext(BrowsingContext aContext,
-                                bool aMoveToBFCache);
-
-    /**
-     * Set the opener of browsing context 'aContext' to the browsing context
-     * with id 'aOpenerId'.
-     */
-    async SetOpenerBrowsingContext(BrowsingContext aContext,
-                                   BrowsingContext aOpenerContext);
-
-    /**
-     * Notify parent to update user gesture activation flag.
-     */
-    async SetUserGestureActivation(BrowsingContext aContext,
-                                   bool aNewValue);
-
 both:
     async CommitBrowsingContextTransaction(BrowsingContext aContext,
                                            BrowsingContextTransaction aTransaction);
 
     async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                        Principal aPrincipal, ClonedMessageData aData);
 
     /**
@@ -1279,16 +1244,41 @@ both:
 
     /**
      * Send a Push error message to all service worker clients in the parent or
      * child.
      */
     async PushError(nsCString scope, Principal principal, nsString message,
                     uint32_t flags);
 
+    /**
+     * Sync the BrowsingContext with id 'aContextId' and name 'aName' to the
+     * parent, and attach it to the BrowsingContext 'aParentContext'. If
+     * 'aParentContext' is 'nullptr' the BrowsingContext is a root in the
+     * BrowsingContext tree. AttachBrowsingContext must only be called at most
+     * once for any child BrowsingContext, and only for BrowsingContexts where
+     * the parent and the child context contains their nsDocShell.
+     */
+    async AttachBrowsingContext(BrowsingContextInitializer aInit);
+
+    /**
+     * Remove the synced BrowsingContext 'aContext' from the parent.
+     * DetachBrowsingContext is only needed to be called once for any
+     * BrowsingContext, since detaching a node in the BrowsingContext detaches
+     * the entire sub-tree rooted at that node. Calling DetachBrowsingContext
+     * with an already detached BrowsingContext effectively does nothing. Note
+     * that it is not an error to call DetachBrowsingContext on a
+     * BrowsingContext belonging to an already detached subtree. The
+     * 'aMoveToBFCache' paramater controls if detaching a BrowsingContext
+     * should move it to the bfcache allowing it to be re-attached if navigated
+     * to.
+     */
+    async DetachBrowsingContext(BrowsingContext aContext,
+                                bool aMoveToBFCache);
+
     async WindowClose(BrowsingContext aContext, bool aTrustedCaller);
     async WindowFocus(BrowsingContext aContext);
     async WindowBlur(BrowsingContext aContext);
     async WindowPostMessage(BrowsingContext aContext, ClonedMessageData aMessage,
                             PostMessageData aData);
 };
 
 }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -349,30 +349,32 @@ already_AddRefed<TabChild> TabChild::Fin
   return tabChild.forget();
 }
 
 /*static*/
 already_AddRefed<TabChild> TabChild::Create(ContentChild* aManager,
                                             const TabId& aTabId,
                                             const TabId& aSameTabGroupAs,
                                             const TabContext& aContext,
+                                            BrowsingContext* aBrowsingContext,
                                             uint32_t aChromeFlags) {
   RefPtr<TabChild> groupChild = FindTabChild(aSameTabGroupAs);
   dom::TabGroup* group = groupChild ? groupChild->TabGroup() : nullptr;
-  RefPtr<TabChild> iframe =
-      new TabChild(aManager, aTabId, group, aContext, aChromeFlags);
+  RefPtr<TabChild> iframe = new TabChild(aManager, aTabId, group, aContext,
+                                         aBrowsingContext, aChromeFlags);
   return iframe.forget();
 }
 
 TabChild::TabChild(ContentChild* aManager, const TabId& aTabId,
                    dom::TabGroup* aTabGroup, const TabContext& aContext,
-                   uint32_t aChromeFlags)
+                   BrowsingContext* aBrowsingContext, uint32_t aChromeFlags)
     : TabContext(aContext),
       mTabGroup(aTabGroup),
       mManager(aManager),
+      mBrowsingContext(aBrowsingContext),
       mChromeFlags(aChromeFlags),
       mMaxTouchPoints(0),
       mLayersId{0},
       mBeforeUnloadListeners(0),
       mDidFakeShow(false),
       mNotified(false),
       mTriedBrowserInit(false),
       mOrientation(hal::eScreenOrientation_PortraitPrimary),
@@ -516,19 +518,18 @@ nsresult TabChild::Init(mozIDOMWindowPro
     return NS_ERROR_FAILURE;
   }
   mPuppetWidget->InfallibleCreate(nullptr,
                                   nullptr,  // no parents
                                   LayoutDeviceIntRect(0, 0, 0, 0),
                                   nullptr  // HandleWidgetEvent
   );
 
-  mWebBrowser =
-      nsWebBrowser::Create(this, mPuppetWidget, OriginAttributesRef(), aParent,
-                           nsIDocShellTreeItem::typeContentWrapper);
+  mWebBrowser = nsWebBrowser::Create(this, mPuppetWidget, OriginAttributesRef(),
+                                     mBrowsingContext);
   nsIWebBrowser* webBrowser = mWebBrowser;
 
   mWebNav = do_QueryInterface(webBrowser);
   NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
 
   // Set the tab context attributes then pass to docShell
   NotifyTabContextUpdated(false);
 
@@ -548,21 +549,16 @@ nsresult TabChild::Init(mozIDOMWindowPro
   docShell->SetAffectPrivateSessionLifetime(
       mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME);
   nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation());
   MOZ_ASSERT(loadContext);
   loadContext->SetPrivateBrowsing(OriginAttributesRef().mPrivateBrowsingId > 0);
   loadContext->SetRemoteTabs(mChromeFlags &
                              nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
 
-  // Send our browsing context to the parent process.
-  RefPtr<BrowsingContext> browsingContext =
-      nsDocShell::Cast(docShell)->GetBrowsingContext();
-  SendRootBrowsingContext(browsingContext);
-
   // Few lines before, baseWindow->Create() will end up creating a new
   // window root in nsGlobalWindow::SetDocShell.
   // Then this chrome event handler, will be inherited to inner windows.
   // We want to also set it to the docshell so that inner windows
   // and any code that has access to the docshell
   // can all listen to the same chrome event handler.
   // XXX: ideally, we would set a chrome event handler earlier,
   // and all windows, even the root one, will use the docshell one.
@@ -634,20 +630,22 @@ void TabChild::UpdateFrameType() {
                              ? nsIDocShell::FRAME_TYPE_BROWSER
                              : nsIDocShell::FRAME_TYPE_REGULAR);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(TabChild)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TabChild, TabChildBase)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebNav)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TabChild, TabChildBase)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebNav)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(TabChild, TabChildBase)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TabChild)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
@@ -923,16 +921,20 @@ TabChild::ProvideWindow(mozIDOMWindowPro
   ContentChild* cc = ContentChild::GetSingleton();
   return cc->ProvideWindowCommon(
       this, aParent, iframeMoz, aChromeFlags, aCalledFromJS, aPositionSpecified,
       aSizeSpecified, aURI, aName, aFeatures, aForceNoOpener, aLoadState,
       aWindowIsNew, aReturn);
 }
 
 void TabChild::DestroyWindow() {
+  if (mBrowsingContext) {
+    mBrowsingContext = nullptr;
+  }
+
   if (mCoalescedMouseEventFlusher) {
     mCoalescedMouseEventFlusher->RemoveObserver();
     mCoalescedMouseEventFlusher = nullptr;
   }
 
   // In case we don't have chance to process all entries, clean all data in
   // the queue.
   while (mToBeDispatchedMouseData.GetSize() > 0) {
@@ -3194,17 +3196,18 @@ PWindowGlobalChild* TabChild::AllocPWind
 
 bool TabChild::DeallocPWindowGlobalChild(PWindowGlobalChild* aActor) {
   // This reference was added in WindowGlobalChild::Create.
   static_cast<WindowGlobalChild*>(aActor)->Release();
   return true;
 }
 
 PBrowserBridgeChild* TabChild::AllocPBrowserBridgeChild(const nsString&,
-                                                        const nsString&) {
+                                                        const nsString&,
+                                                        BrowsingContext*) {
   MOZ_CRASH(
       "We should never be manually allocating PBrowserBridgeChild actors");
   return nullptr;
 }
 
 bool TabChild::DeallocPBrowserBridgeChild(PBrowserBridgeChild* aActor) {
   // This reference was added in BrowserBridgeChild::Create.
   static_cast<BrowserBridgeChild*>(aActor)->Release();
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -227,25 +227,27 @@ class TabChild final : public TabChildBa
   // Return a list of all active TabChildren.
   static nsTArray<RefPtr<TabChild>> GetAll();
 
  public:
   /**
    * Create a new TabChild object.
    */
   TabChild(ContentChild* aManager, const TabId& aTabId, TabGroup* aTabGroup,
-           const TabContext& aContext, uint32_t aChromeFlags);
+           const TabContext& aContext, BrowsingContext* aBrowsingContext,
+           uint32_t aChromeFlags);
 
   nsresult Init(mozIDOMWindowProxy* aParent);
 
   /** Return a TabChild with the given attributes. */
   static already_AddRefed<TabChild> Create(ContentChild* aManager,
                                            const TabId& aTabId,
                                            const TabId& aSameTabGroupAs,
                                            const TabContext& aContext,
+                                           BrowsingContext* aBrowsingContext,
                                            uint32_t aChromeFlags);
 
   // Let managees query if it is safe to send messages.
   bool IsDestroyed() const { return mDestroyed; }
 
   const TabId GetTabId() const {
     MOZ_ASSERT(mUniqueId != 0);
     return mUniqueId;
@@ -667,17 +669,18 @@ class TabChild final : public TabChildBa
   virtual ~TabChild();
 
   virtual PWindowGlobalChild* AllocPWindowGlobalChild(
       const WindowGlobalInit& aInit) override;
 
   virtual bool DeallocPWindowGlobalChild(PWindowGlobalChild* aActor) override;
 
   virtual PBrowserBridgeChild* AllocPBrowserBridgeChild(
-      const nsString& aName, const nsString& aRemoteType) override;
+      const nsString& aName, const nsString& aRemoteType,
+      BrowsingContext* aBrowsingContext) override;
 
   virtual bool DeallocPBrowserBridgeChild(PBrowserBridgeChild* aActor) override;
 
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
 
   virtual mozilla::ipc::IPCResult RecvSetDocShellIsActive(
       const bool& aIsActive) override;
 
@@ -800,16 +803,17 @@ class TabChild final : public TabChildBa
 
   TextureFactoryIdentifier mTextureFactoryIdentifier;
   RefPtr<nsWebBrowser> mWebBrowser;
   nsCOMPtr<nsIWebNavigation> mWebNav;
   RefPtr<mozilla::dom::TabGroup> mTabGroup;
   RefPtr<PuppetWidget> mPuppetWidget;
   nsCOMPtr<nsIURI> mLastURI;
   RefPtr<ContentChild> mManager;
+  RefPtr<BrowsingContext> mBrowsingContext;
   uint32_t mChromeFlags;
   uint32_t mMaxTouchPoints;
   layers::LayersId mLayersId;
   int64_t mBeforeUnloadListeners;
   CSSRect mUnscaledOuterRect;
   Maybe<bool> mLayersConnected;
   bool mDidFakeShow;
   bool mNotified;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -144,17 +144,19 @@ namespace mozilla {
 namespace dom {
 
 TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr;
 
 NS_IMPL_ISUPPORTS(TabParent, nsITabParent, nsIAuthPromptProvider,
                   nsISupportsWeakReference)
 
 TabParent::TabParent(ContentParent* aManager, const TabId& aTabId,
-                     const TabContext& aContext, uint32_t aChromeFlags,
+                     const TabContext& aContext,
+                     CanonicalBrowsingContext* aBrowsingContext,
+                     uint32_t aChromeFlags,
                      BrowserBridgeParent* aBrowserBridgeParent)
     : TabContext(aContext),
       mFrameElement(nullptr),
       mContentCache(*this),
       mRect(0, 0, 0, 0),
       mDimensions(0, 0),
       mOrientation(0),
       mDPI(0),
@@ -163,16 +165,17 @@ TabParent::TabParent(ContentParent* aMan
       mUpdatedDimensions(false),
       mSizeMode(nsSizeMode_Normal),
       mManager(aManager),
       mDocShellIsActive(false),
       mMarkedDestroying(false),
       mIsDestroyed(false),
       mChromeFlags(aChromeFlags),
       mDragValid(false),
+      mBrowsingContext(aBrowsingContext),
       mBrowserBridgeParent(aBrowserBridgeParent),
       mTabId(aTabId),
       mCreatingWindow(false),
       mCursor(eCursorInvalid),
       mCustomCursorHotspotX(0),
       mCustomCursorHotspotY(0),
       mTabSetsCursor(false),
       mHasContentOpener(false)
@@ -1013,23 +1016,25 @@ PWindowGlobalParent* TabParent::AllocPWi
 bool TabParent::DeallocPWindowGlobalParent(PWindowGlobalParent* aActor) {
   // Free reference from AllocPWindowGlobalParent.
   static_cast<WindowGlobalParent*>(aActor)->Release();
   return true;
 }
 
 IPCResult TabParent::RecvPBrowserBridgeConstructor(
     PBrowserBridgeParent* aActor, const nsString& aName,
-    const nsString& aRemoteType) {
-  static_cast<BrowserBridgeParent*>(aActor)->Init(aName, aRemoteType);
+    const nsString& aRemoteType, BrowsingContext* aBrowsingContext) {
+  static_cast<BrowserBridgeParent*>(aActor)->Init(
+      aName, aRemoteType, CanonicalBrowsingContext::Cast(aBrowsingContext));
   return IPC_OK();
 }
 
 PBrowserBridgeParent* TabParent::AllocPBrowserBridgeParent(
-    const nsString& aName, const nsString& aRemoteType) {
+    const nsString& aName, const nsString& aRemoteType,
+    BrowsingContext* aBrowsingContext) {
   // Reference freed in DeallocPBrowserBridgeParent.
   return do_AddRef(new BrowserBridgeParent()).take();
 }
 
 bool TabParent::DeallocPBrowserBridgeParent(PBrowserBridgeParent* aActor) {
   // Free reference from AllocPBrowserBridgeParent.
   static_cast<BrowserBridgeParent*>(aActor)->Release();
   return true;
@@ -3502,24 +3507,16 @@ mozilla::ipc::IPCResult TabParent::RecvS
 mozilla::ipc::IPCResult TabParent::RecvGetSystemFont(nsCString* aFontName) {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     widget->GetSystemFont(*aFontName);
   }
   return IPC_OK();
 }
 
-mozilla::ipc::IPCResult TabParent::RecvRootBrowsingContext(
-    BrowsingContext* aBrowsingContext) {
-  MOZ_ASSERT(!mBrowsingContext, "May only set browsing context once!");
-  mBrowsingContext = CanonicalBrowsingContext::Cast(aBrowsingContext);
-  MOZ_ASSERT(mBrowsingContext, "Invalid ID!");
-  return IPC_OK();
-}
-
 NS_IMETHODIMP
 FakeChannel::OnAuthAvailable(nsISupports* aContext,
                              nsIAuthInformation* aAuthInfo) {
   nsAuthInformationHolder* holder =
       static_cast<nsAuthInformationHolder*>(aAuthInfo);
 
   if (!net::gNeckoChild->SendOnAuthAvailable(
           mCallbackId, holder->User(), holder->Password(), holder->Domain())) {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -98,17 +98,18 @@ class TabParent final : public PBrowserP
   struct AutoUseNewTab;
 
   // nsITabParent
   NS_DECL_NSITABPARENT
   // nsIDOMEventListener interfaces
   NS_DECL_NSIDOMEVENTLISTENER
 
   TabParent(ContentParent* aManager, const TabId& aTabId,
-            const TabContext& aContext, uint32_t aChromeFlags,
+            const TabContext& aContext,
+            CanonicalBrowsingContext* aBrowsingContext, uint32_t aChromeFlags,
             BrowserBridgeParent* aBrowserBridgeParent = nullptr);
 
   Element* GetOwnerElement() const { return mFrameElement; }
   already_AddRefed<nsPIDOMWindowOuter> GetParentWindowOuter();
 
   void SetOwnerElement(Element* aElement);
 
   void CacheFrameLoader(nsFrameLoader* aFrameLoader);
@@ -314,23 +315,24 @@ class TabParent final : public PBrowserP
   PWindowGlobalParent* AllocPWindowGlobalParent(const WindowGlobalInit& aInit);
 
   bool DeallocPWindowGlobalParent(PWindowGlobalParent* aActor);
 
   virtual mozilla::ipc::IPCResult RecvPWindowGlobalConstructor(
       PWindowGlobalParent* aActor, const WindowGlobalInit& aInit) override;
 
   PBrowserBridgeParent* AllocPBrowserBridgeParent(
-      const nsString& aPresentationURL, const nsString& aRemoteType);
+      const nsString& aPresentationURL, const nsString& aRemoteType,
+      BrowsingContext* aBrowsingContext);
 
   bool DeallocPBrowserBridgeParent(PBrowserBridgeParent* aActor);
 
   virtual mozilla::ipc::IPCResult RecvPBrowserBridgeConstructor(
       PBrowserBridgeParent* aActor, const nsString& aPresentationURL,
-      const nsString& aRemoteType) override;
+      const nsString& aRemoteType, BrowsingContext* aBrowsingContext) override;
 
   void LoadURL(nsIURI* aURI);
 
   void InitRendering();
   void MaybeShowFrame();
 
   // XXX/cjones: it's not clear what we gain by hiding these
   // message-sending functions under a layer of indirection and
@@ -625,18 +627,16 @@ class TabParent final : public PBrowserP
                                             const int32_t& aX,
                                             const int32_t& aY,
                                             const int32_t& aCx,
                                             const int32_t& aCy);
 
   mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt(
       const nsCString& aFirstPartyURI, const bool& aHideDoorHanger);
 
-  mozilla::ipc::IPCResult RecvRootBrowsingContext(BrowsingContext* aContext);
-
   mozilla::ipc::IPCResult RecvSetSystemFont(const nsCString& aFontName);
   mozilla::ipc::IPCResult RecvGetSystemFont(nsCString* aFontName);
 
   mozilla::ipc::IPCResult RecvVisitURI(const URIParams& aURI,
                                        const Maybe<URIParams>& aLastVisitedURI,
                                        const uint32_t& aFlags);
 
   mozilla::ipc::IPCResult RecvQueryVisitedState(
--- a/dom/ipc/tests/test_force_oop_iframe.html
+++ b/dom/ipc/tests/test_force_oop_iframe.html
@@ -8,17 +8,18 @@
 </head>
 <body>
 
 <script type="application/javascript">
 "use strict";
 /* eslint-env mozilla/frame-script */
 
 add_task(async function() {
-  await SpecialPowers.pushPrefEnv({"set": [["fission.oopif.attribute", true]]});
+  await SpecialPowers.pushPrefEnv({"set": [["fission.oopif.attribute", true],
+                                           ["dom.ipc.processCount", 10000]]});
 
   // This iframe should be loaded out of process. Unfortunately as of the time
   // of this test's creation, many different events which we could use to detect
   // this load have not been implemented yet.
   let contentCreated = ChromeTask.spawn(null, async function() {
     let wgp = await new Promise(resolve => {
       function observer(parent) {
         info("WGP with origin: " + parent.documentPrincipal.origin);
@@ -43,13 +44,22 @@ add_task(async function() {
   document.body.appendChild(iframe);
 
   // Check that this isn't loaded in-process, or using a nested tabParent object.
   let frameLoader = SpecialPowers.wrap(iframe).frameLoader;
   is(frameLoader.docShell, null);
   is(frameLoader.tabParent, null);
 
   await contentCreated;
+
+  ok(frameLoader.browsingContext, "Has BrowsingContext");
+  ok(frameLoader.browsingContext.parent, "BrowsingContext has parent");
+
+  let wgc = SpecialPowers.wrap(window).getWindowGlobalChild();
+  ok(wgc, "we have a WindowGlobalChild");
+  is(SpecialPowers.unwrap(wgc.browsingContext),
+     SpecialPowers.unwrap(frameLoader.browsingContext.parent),
+     "BrowsingContext matches");
 });
 
 </script>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/media/gtest/TestBufferReader.cpp
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "BufferReader.h"
+
+TEST(BufferReader, ReaderCursor) {
+  // Allocate a buffer and create a BufferReader.
+  const size_t BUFFER_SIZE = 10;
+  uint8_t buffer[BUFFER_SIZE] = {0};
+
+  const uint8_t* const HEAD = reinterpret_cast<uint8_t*>(buffer);
+  const uint8_t* const TAIL = HEAD + BUFFER_SIZE;
+
+  BufferReader reader(HEAD, BUFFER_SIZE);
+  ASSERT_EQ(reader.Offset(), static_cast<size_t>(0));
+  ASSERT_EQ(reader.Peek(BUFFER_SIZE), HEAD);
+
+  // Keep reading to the end, and make sure the final read failed.
+  const size_t READ_SIZE = 4;
+  ASSERT_NE(BUFFER_SIZE % READ_SIZE, static_cast<size_t>(0));
+  for (const uint8_t* ptr = reader.Peek(0); ptr != nullptr;
+       ptr = reader.Read(READ_SIZE))
+    ;
+
+  // Check the reading cursor of the BufferReader is correct
+  // after reading and seeking.
+  const uint8_t* tail = reader.Peek(0);
+  const uint8_t* head = reader.Seek(0);
+
+  EXPECT_EQ(head, HEAD);
+  EXPECT_EQ(tail, TAIL);
+}
\ No newline at end of file
--- a/dom/media/gtest/TestMP3Demuxer.cpp
+++ b/dom/media/gtest/TestMP3Demuxer.cpp
@@ -42,18 +42,21 @@ class MockMP3StreamMediaResource
 
   int64_t GetLength() override { return -1; }
 
  protected:
   virtual ~MockMP3StreamMediaResource() {}
 };
 
 struct MP3Resource {
+  enum HeaderType { NONE, XING, VBRI };
+
   const char* mFilePath;
   bool mIsVBR;
+  HeaderType mHeaderType;
   int64_t mFileSize;
   int32_t mMPEGLayer;
   int32_t mMPEGVersion;
   uint8_t mID3MajorVersion;
   uint8_t mID3MinorVersion;
   uint8_t mID3Flags;
   uint32_t mID3Size;
 
@@ -78,16 +81,17 @@ struct MP3Resource {
 
 class MP3DemuxerTest : public ::testing::Test {
  protected:
   void SetUp() override {
     {
       MP3Resource res;
       res.mFilePath = "noise.mp3";
       res.mIsVBR = false;
+      res.mHeaderType = MP3Resource::NONE;
       res.mFileSize = 965257;
       res.mMPEGLayer = 3;
       res.mMPEGVersion = 1;
       res.mID3MajorVersion = 3;
       res.mID3MinorVersion = 0;
       res.mID3Flags = 0;
       res.mID3Size = 2141;
       res.mDuration = 30067000;
@@ -122,16 +126,17 @@ class MP3DemuxerTest : public ::testing:
       MP3Resource res;
       // This file trips up the MP3 demuxer if ID3v2 tags aren't properly
       // skipped. If skipping is not properly implemented, depending on the
       // strictness of the MPEG frame parser a false sync will be detected
       // somewhere within the metadata at or after 112087, or failing that, at
       // the artificially added extraneous header at 114532.
       res.mFilePath = "id3v2header.mp3";
       res.mIsVBR = false;
+      res.mHeaderType = MP3Resource::NONE;
       res.mFileSize = 191302;
       res.mMPEGLayer = 3;
       res.mMPEGVersion = 1;
       res.mID3MajorVersion = 3;
       res.mID3MinorVersion = 0;
       res.mID3Flags = 0;
       res.mID3Size = 115304;
       res.mDuration = 3166167;
@@ -161,16 +166,17 @@ class MP3DemuxerTest : public ::testing:
       streamRes.mDemuxer = new MP3TrackDemuxer(streamRes.mResource);
       mTargets.push_back(streamRes);
     }
 
     {
       MP3Resource res;
       res.mFilePath = "noise_vbr.mp3";
       res.mIsVBR = true;
+      res.mHeaderType = MP3Resource::XING;
       res.mFileSize = 583679;
       res.mMPEGLayer = 3;
       res.mMPEGVersion = 1;
       res.mID3MajorVersion = 3;
       res.mID3MinorVersion = 0;
       res.mID3Flags = 0;
       res.mID3Size = 2221;
       res.mDuration = 30081000;
@@ -199,16 +205,17 @@ class MP3DemuxerTest : public ::testing:
       streamRes.mDemuxer = new MP3TrackDemuxer(streamRes.mResource);
       mTargets.push_back(streamRes);
     }
 
     {
       MP3Resource res;
       res.mFilePath = "small-shot.mp3";
       res.mIsVBR = true;
+      res.mHeaderType = MP3Resource::XING;
       res.mFileSize = 6825;
       res.mMPEGLayer = 3;
       res.mMPEGVersion = 1;
       res.mID3MajorVersion = 4;
       res.mID3MinorVersion = 0;
       res.mID3Flags = 0;
       res.mID3Size = 24;
       res.mDuration = 336686;
@@ -239,16 +246,17 @@ class MP3DemuxerTest : public ::testing:
     }
 
     {
       MP3Resource res;
       // This file contains a false frame sync at 34, just after the ID3 tag,
       // which should be identified as a false positive and skipped.
       res.mFilePath = "small-shot-false-positive.mp3";
       res.mIsVBR = true;
+      res.mHeaderType = MP3Resource::XING;
       res.mFileSize = 6845;
       res.mMPEGLayer = 3;
       res.mMPEGVersion = 1;
       res.mID3MajorVersion = 4;
       res.mID3MinorVersion = 0;
       res.mID3Flags = 0;
       res.mID3Size = 24;
       res.mDuration = 336686;
@@ -277,16 +285,17 @@ class MP3DemuxerTest : public ::testing:
       streamRes.mDemuxer = new MP3TrackDemuxer(streamRes.mResource);
       mTargets.push_back(streamRes);
     }
 
     {
       MP3Resource res;
       res.mFilePath = "small-shot-partial-xing.mp3";
       res.mIsVBR = true;
+      res.mHeaderType = MP3Resource::XING;
       res.mFileSize = 6825;
       res.mMPEGLayer = 3;
       res.mMPEGVersion = 1;
       res.mID3MajorVersion = 4;
       res.mID3MinorVersion = 0;
       res.mID3Flags = 0;
       res.mID3Size = 24;
       res.mDuration = 336686;
@@ -311,16 +320,55 @@ class MP3DemuxerTest : public ::testing:
       res.mDemuxer = new MP3TrackDemuxer(res.mResource);
       mTargets.push_back(res);
 
       streamRes.mResource = new MockMP3StreamMediaResource(streamRes.mFilePath);
       streamRes.mDemuxer = new MP3TrackDemuxer(streamRes.mResource);
       mTargets.push_back(streamRes);
     }
 
+    {
+      MP3Resource res;
+      res.mFilePath = "test_vbri.mp3";
+      res.mIsVBR = true;
+      res.mHeaderType = MP3Resource::VBRI;
+      res.mFileSize = 16519;
+      res.mMPEGLayer = 3;
+      res.mMPEGVersion = 1;
+      res.mID3MajorVersion = 3;
+      res.mID3MinorVersion = 0;
+      res.mID3Flags = 0;
+      res.mID3Size = 4202;
+      res.mDuration = 783660;
+      res.mDurationError = 0.01f;
+      res.mSeekError = 0.02f;
+      res.mSampleRate = 44100;
+      res.mSamplesPerFrame = 1152;
+      res.mNumSamples = 29;
+      res.mNumTrailingFrames = 0;
+      res.mBitrate = 0;
+      res.mSlotSize = 1;
+      res.mPrivate = 0;
+      const int syncs[] = {4212, 4734, 5047, 5464, 5986, 6403};
+      res.mSyncOffsets.insert(res.mSyncOffsets.begin(), syncs, syncs + 6);
+
+      // VBR stream resources contain header info on total frames numbers, which
+      // is used to estimate the total duration.
+      MP3Resource streamRes = res;
+      streamRes.mFileSize = -1;
+
+      res.mResource = new MockMP3MediaResource(res.mFilePath);
+      res.mDemuxer = new MP3TrackDemuxer(res.mResource);
+      mTargets.push_back(res);
+
+      streamRes.mResource = new MockMP3StreamMediaResource(streamRes.mFilePath);
+      streamRes.mDemuxer = new MP3TrackDemuxer(streamRes.mResource);
+      mTargets.push_back(streamRes);
+    }
+
     for (auto& target : mTargets) {
       ASSERT_EQ(NS_OK, target.mResource->Open());
       ASSERT_TRUE(target.mDemuxer->Init());
     }
   }
 
   std::vector<MP3Resource> mTargets;
 };
@@ -342,22 +390,25 @@ TEST_F(MP3DemuxerTest, ID3Tags) {
 
 TEST_F(MP3DemuxerTest, VBRHeader) {
   for (const auto& target : mTargets) {
     RefPtr<MediaRawData> frame(target.mDemuxer->DemuxSample());
     ASSERT_TRUE(frame);
 
     const auto& vbr = target.mDemuxer->VBRInfo();
 
-    if (target.mIsVBR) {
+    if (target.mHeaderType == MP3Resource::XING) {
       EXPECT_EQ(FrameParser::VBRHeader::XING, vbr.Type());
       // TODO: find reference number which accounts for trailing headers.
       // EXPECT_EQ(target.mNumSamples / target.mSamplesPerFrame,
       // vbr.NumAudioFrames().value());
-    } else {
+    } else if (target.mHeaderType == MP3Resource::VBRI) {
+      EXPECT_TRUE(target.mIsVBR);
+      EXPECT_EQ(FrameParser::VBRHeader::VBRI, vbr.Type());
+    } else {  // MP3Resource::NONE
       EXPECT_EQ(FrameParser::VBRHeader::NONE, vbr.Type());
       EXPECT_FALSE(vbr.NumAudioFrames());
     }
   }
 }
 
 TEST_F(MP3DemuxerTest, FrameParsing) {
   for (const auto& target : mTargets) {
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -18,16 +18,17 @@ UNIFIED_SOURCES += [
     'TestAudioBuffers.cpp',
     'TestAudioCompactor.cpp',
     'TestAudioMixer.cpp',
     'TestAudioPacketizer.cpp',
     'TestAudioSegment.cpp',
     'TestAudioTrackEncoder.cpp',
     'TestBitWriter.cpp',
     'TestBlankVideoDataCreator.cpp',
+    'TestBufferReader.cpp',
     'TestCDMStorage.cpp',
     'TestDataMutex.cpp',
     'TestGMPCrossOrigin.cpp',
     'TestGMPRemoveAndDelete.cpp',
     'TestGMPUtils.cpp',
     'TestGroupId.cpp',
     'TestIntervalSet.cpp',
     'TestMediaDataDecoder.cpp',
@@ -68,16 +69,17 @@ TEST_HARNESS_FILES.gtest += [
     'short-zero-inband.mov',
     'small-shot-false-positive.mp3',
     'small-shot-partial-xing.mp3',
     'small-shot.mp3',
     'test.webm',
     'test_case_1224361.vp8.ivf',
     'test_case_1224363.vp8.ivf',
     'test_case_1224369.vp8.ivf',
+    'test_vbri.mp3',
 ]
 
 TEST_DIRS += [
     'mp4_demuxer',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..efd74503385c9d8c6afaf59a8923cf67ebd71805
GIT binary patch
literal 16519
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
RO7CGzPyM{||8^tz{{j-3?G*q3
--- a/dom/media/mp3/MP3Demuxer.cpp
+++ b/dom/media/mp3/MP3Demuxer.cpp
@@ -292,54 +292,59 @@ MP3TrackDemuxer::SkipToNextRandomAccessP
   return SkipAccessPointPromise::CreateAndReject(
       SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
 }
 
 int64_t MP3TrackDemuxer::GetResourceOffset() const { return mOffset; }
 
 TimeIntervals MP3TrackDemuxer::GetBuffered() {
   AutoPinned<MediaResource> stream(mSource.GetResource());
-  TimeIntervals buffered;
+  TimeIntervals duration;
+  duration += TimeInterval(TimeUnit(), Duration());
 
   if (Duration() > TimeUnit() && stream->IsDataCachedToEndOfResource(0)) {
     // Special case completely cached files. This also handles local files.
-    buffered += TimeInterval(TimeUnit(), Duration());
     MP3LOGV("buffered = [[%" PRId64 ", %" PRId64 "]]",
             TimeUnit().ToMicroseconds(), Duration().ToMicroseconds());
-    return buffered;
+    return duration;
   }
 
+  TimeIntervals buffered;
   MediaByteRangeSet ranges;
   nsresult rv = stream->GetCachedRanges(ranges);
   NS_ENSURE_SUCCESS(rv, buffered);
 
   for (const auto& range : ranges) {
     if (range.IsEmpty()) {
       continue;
     }
     TimeUnit start = Duration(FrameIndexFromOffset(range.mStart));
     TimeUnit end = Duration(FrameIndexFromOffset(range.mEnd));
     MP3LOGV("buffered += [%" PRId64 ", %" PRId64 "]", start.ToMicroseconds(),
             end.ToMicroseconds());
     buffered += TimeInterval(start, end);
   }
 
-  return buffered;
+  // If the number of frames presented in header is valid, the duration
+  // calculated from it should be the maximal duration.
+  return ValidNumAudioFrames().isSome() && buffered.GetEnd() > duration.GetEnd()
+             ? duration
+             : buffered;
 }
 
 int64_t MP3TrackDemuxer::StreamLength() const { return mSource.GetLength(); }
 
 TimeUnit MP3TrackDemuxer::Duration() const {
   if (!mNumParsedFrames) {
     return TimeUnit::FromMicroseconds(-1);
   }
 
   int64_t numFrames = 0;
-  const auto numAudioFrames = mParser.VBRInfo().NumAudioFrames();
-  if (mParser.VBRInfo().IsValid() && numAudioFrames.valueOr(0) + 1 > 1) {
+  const auto numAudioFrames = ValidNumAudioFrames();
+  if (numAudioFrames.isSome()) {
     // VBR headers don't include the VBR header frame.
     numFrames = numAudioFrames.value() + 1;
     return Duration(numFrames);
   }
 
   const int64_t streamLen = StreamLength();
   if (streamLen < 0) {  // Live streams.
     // Unknown length, we can't estimate duration.
@@ -723,12 +728,19 @@ double MP3TrackDemuxer::AverageFrameLeng
   const auto& vbr = mParser.VBRInfo();
   if (vbr.IsComplete() && vbr.NumAudioFrames().value() + 1) {
     return static_cast<double>(vbr.NumBytes().value()) /
            (vbr.NumAudioFrames().value() + 1);
   }
   return 0.0;
 }
 
+Maybe<uint32_t> MP3TrackDemuxer::ValidNumAudioFrames() const {
+  return mParser.VBRInfo().IsValid() &&
+                 mParser.VBRInfo().NumAudioFrames().valueOr(0) + 1 > 1
+             ? mParser.VBRInfo().NumAudioFrames()
+             : Maybe<uint32_t>();
+}
+
 }  // namespace mozilla
 
 #undef MP3LOG
 #undef MP3LOGV
--- a/dom/media/mp3/MP3Demuxer.h
+++ b/dom/media/mp3/MP3Demuxer.h
@@ -117,16 +117,20 @@ class MP3TrackDemuxer : public MediaTrac
 
   // Reads aSize bytes into aBuffer from the source starting at aOffset.
   // Returns the actual size read.
   int32_t Read(uint8_t* aBuffer, int64_t aOffset, int32_t aSize);
 
   // Returns the average frame length derived from the previously parsed frames.
   double AverageFrameLength() const;
 
+  // Returns the number of frames reported by the header if it's valid. Nothing
+  // otherwise.
+  Maybe<uint32_t> ValidNumAudioFrames() const;
+
   // The (hopefully) MPEG resource.
   MediaResourceIndex mSource;
 
   // MPEG frame parser used to detect frames and extract side info.
   FrameParser mParser;
 
   // Whether we've locked onto a valid sequence of frames or not.
   bool mFrameLock;
--- a/dom/media/mp3/MP3FrameParser.cpp
+++ b/dom/media/mp3/MP3FrameParser.cpp
@@ -8,16 +8,17 @@
 
 #include <algorithm>
 #include <inttypes.h>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Pair.h"
 #include "mozilla/ResultExtensions.h"
+#include "mozilla/ScopeExit.h"
 #include "VideoUtils.h"
 
 extern mozilla::LazyLogModule gMediaDemuxerLog;
 #define MP3LOG(msg, ...) \
   MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, ("MP3Demuxer " msg, ##__VA_ARGS__))
 #define MP3LOGV(msg, ...)                      \
   MOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, \
           ("MP3Demuxer " msg, ##__VA_ARGS__))
@@ -77,18 +78,17 @@ Result<bool, nsresult> FrameParser::Pars
   MOZ_ASSERT(aReader && aBytesToSkip);
   *aBytesToSkip = 0;
 
   if (!mID3Parser.Header().Size() && !mFirstFrame.Length()) {
     // No MP3 frames have been parsed yet, look for ID3v2 headers at file begin.
     // ID3v1 tags may only be at file end.
     // TODO: should we try to read ID3 tags at end of file/mid-stream, too?
     const size_t prevReaderOffset = aReader->Offset();
-    uint32_t tagSize;
-    MOZ_TRY_VAR(tagSize, mID3Parser.Parse(aReader));
+    const uint32_t tagSize = mID3Parser.Parse(aReader).unwrapOr(0);
     if (!!tagSize) {
       // ID3 tag found, skip past it.
       const uint32_t skipSize = tagSize - ID3Parser::ID3Header::SIZE;
 
       if (skipSize > aReader->Remaining()) {
         // Skipping across the ID3v2 tag would take us past the end of the
         // buffer, therefore we return immediately and let the calling function
         // handle skipping the rest of the tag.
@@ -351,17 +351,20 @@ Result<bool, nsresult> FrameParser::VBRH
   enum Flags {
     NUM_FRAMES = 0x01,
     NUM_BYTES = 0x02,
     TOC = 0x04,
     VBR_SCALE = 0x08
   };
 
   MOZ_ASSERT(aReader);
+
+  // Seek backward to the original position before leaving this scope.
   const size_t prevReaderOffset = aReader->Offset();
+  auto scopeExit = MakeScopeExit([&] { aReader->Seek(prevReaderOffset); });
 
   // We have to search for the Xing header as its position can change.
   for (auto res = aReader->PeekU32();
        res.isOk() && res.unwrap() != XING_TAG && res.unwrap() != INFO_TAG;) {
     aReader->Read(1);
     res = aReader->PeekU32();
   }
 
@@ -397,17 +400,16 @@ Result<bool, nsresult> FrameParser::VBRH
     }
   }
   if (flags & VBR_SCALE) {
     uint32_t scale;
     MOZ_TRY_VAR(scale, aReader->ReadU32());
     mScale = Some(scale);
   }
 
-  aReader->Seek(prevReaderOffset);
   return mType == XING;
 }
 
 Result<bool, nsresult> FrameParser::VBRHeader::ParseVBRI(
     BufferReader* aReader) {
   static const uint32_t TAG = BigEndian::readUint32("VBRI");
   static const uint32_t OFFSET = 32 + FrameParser::FrameHeader::SIZE;
   static const uint32_t FRAME_COUNT_OFFSET = OFFSET + 14;
@@ -416,33 +418,34 @@ Result<bool, nsresult> FrameParser::VBRH
   MOZ_ASSERT(aReader);
   // ParseVBRI assumes that the ByteReader offset points to the beginning of a
   // frame, therefore as a simple check, we look for the presence of a frame
   // sync at that position.
   auto sync = aReader->PeekU16();
   if (sync.isOk()) {  // To avoid compiler complains 'set but unused'.
     MOZ_ASSERT((sync.unwrap() & 0xFFE0) == 0xFFE0);
   }
+
+  // Seek backward to the original position before leaving this scope.
   const size_t prevReaderOffset = aReader->Offset();
+  auto scopeExit = MakeScopeExit([&] { aReader->Seek(prevReaderOffset); });
 
   // VBRI have a fixed relative position, so let's check for it there.
   if (aReader->Remaining() > MIN_FRAME_SIZE) {
     aReader->Seek(prevReaderOffset + OFFSET);
     uint32_t tag, frames;
     MOZ_TRY_VAR(tag, aReader->ReadU32());
     if (tag == TAG) {
       aReader->Seek(prevReaderOffset + FRAME_COUNT_OFFSET);
       MOZ_TRY_VAR(frames, aReader->ReadU32());
       mNumAudioFrames = Some(frames);
       mType = VBRI;
-      aReader->Seek(prevReaderOffset);
       return true;
     }
   }
-  aReader->Seek(prevReaderOffset);
   return false;
 }
 
 bool FrameParser::VBRHeader::Parse(BufferReader* aReader) {
   auto res = MakePair(ParseVBRI(aReader), ParseXing(aReader));
   const bool rv = (res.first().isOk() && res.first().unwrap()) ||
                   (res.second().isOk() && res.second().unwrap());
   if (rv) {
--- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -1239,17 +1239,17 @@ nsresult nsWebBrowserPersist::SaveURIInt
   // based on the current state of the prefs/permissions.
   nsCOMPtr<nsICookieSettings> cookieSettings =
       mozilla::net::CookieSettings::Create();
 
   // Open a channel to the URI
   nsCOMPtr<nsIChannel> inputChannel;
   rv = NS_NewChannel(getter_AddRefs(inputChannel), aURI, aTriggeringPrincipal,
                      nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
-                     nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD, cookieSettings,
+                     aContentPolicyType, cookieSettings,
                      nullptr,  // aPerformanceStorage
                      nullptr,  // aLoadGroup
                      static_cast<nsIInterfaceRequestor *>(this), loadFlags);
 
   nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel =
       do_QueryInterface(inputChannel);
   if (pbChannel) {
     pbChannel->SetPrivate(aIsPrivate);
--- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
@@ -184,26 +184,29 @@ class RemoteWorkerChild::InitializeWorke
     mActor->ShutdownOnWorker();
     return WorkerRunnable::Cancel();
   }
 
   RefPtr<RemoteWorkerChild> mActor;
 };
 
 RemoteWorkerChild::RemoteWorkerChild()
-    : mIPCActive(true), mWorkerState(ePending) {
+    : mIPCActive(true), mSharedData("RemoteWorkerChild::mSharedData") {
   MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
 }
 
+RemoteWorkerChild::SharedData::SharedData() : mWorkerState(ePending) {}
+
 RemoteWorkerChild::~RemoteWorkerChild() {
   nsCOMPtr<nsIEventTarget> target =
       SystemGroup::EventTargetFor(TaskCategory::Other);
 
+  const auto lock = mSharedData.Lock();
   NS_ProxyRelease("RemoteWorkerChild::mWorkerPrivate", target,
-                  mWorkerPrivate.forget());
+                  lock->mWorkerPrivate.forget());
 }
 
 void RemoteWorkerChild::ActorDestroy(ActorDestroyReason aWhy) {
   MOZ_ACCESS_THREAD_BOUND(mLauncherData, data);
   mIPCActive = false;
   data->mPendingOps.Clear();
 }
 
@@ -308,76 +311,84 @@ nsresult RemoteWorkerChild::ExecWorkerOn
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   AutoJSAPI jsapi;
   jsapi.Init();
 
   ErrorResult error;
-  mWorkerPrivate = WorkerPrivate::Constructor(
+  const auto lock = mSharedData.Lock();
+  lock->mWorkerPrivate = WorkerPrivate::Constructor(
       jsapi.cx(), aData.originalScriptURL(), false,
       aData.isSharedWorker() ? WorkerTypeShared : WorkerTypeService,
       aData.name(), VoidCString(), &info, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   RefPtr<InitializeWorkerRunnable> runnable =
-      new InitializeWorkerRunnable(mWorkerPrivate, this);
+      new InitializeWorkerRunnable(lock->mWorkerPrivate, this);
   if (NS_WARN_IF(!runnable->Dispatch())) {
     return NS_ERROR_FAILURE;
   }
 
-  mWorkerPrivate->SetRemoteWorkerController(this);
+  lock->mWorkerPrivate->SetRemoteWorkerController(this);
   return NS_OK;
 }
 
 void RemoteWorkerChild::InitializeOnWorker(WorkerPrivate* aWorkerPrivate) {
   MOZ_ASSERT(aWorkerPrivate);
   aWorkerPrivate->AssertIsOnWorkerThread();
 
   RefPtr<RemoteWorkerChild> self = this;
-  mWorkerRef = WeakWorkerRef::Create(mWorkerPrivate,
-                                     [self]() { self->ShutdownOnWorker(); });
+  {
+    const auto lock = mSharedData.Lock();
+    mWorkerRef = WeakWorkerRef::Create(lock->mWorkerPrivate,
+                                       [self]() { self->ShutdownOnWorker(); });
+  }
 
   if (NS_WARN_IF(!mWorkerRef)) {
     CreationFailedOnAnyThread();
     ShutdownOnWorker();
     return;
   }
 
   CreationSucceededOnAnyThread();
 }
 
 void RemoteWorkerChild::ShutdownOnWorker() {
-  MOZ_ASSERT(mWorkerPrivate);
-  mWorkerPrivate->AssertIsOnWorkerThread();
+  const auto lock = mSharedData.Lock();
+  MOZ_ASSERT(lock->mWorkerPrivate);
+  lock->mWorkerPrivate->AssertIsOnWorkerThread();
 
   // This will release the worker.
   mWorkerRef = nullptr;
 
   nsCOMPtr<nsIEventTarget> target =
       SystemGroup::EventTargetFor(TaskCategory::Other);
 
   NS_ProxyRelease("RemoteWorkerChild::mWorkerPrivate", target,
-                  mWorkerPrivate.forget());
+                  lock->mWorkerPrivate.forget());
 
   RefPtr<RemoteWorkerChild> self = this;
   nsCOMPtr<nsIRunnable> r =
       NS_NewRunnableFunction("RemoteWorkerChild::ShutdownOnWorker",
                              [self]() { self->WorkerTerminated(); });
 
   RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
 }
 
 void RemoteWorkerChild::WorkerTerminated() {
   MOZ_ACCESS_THREAD_BOUND(mLauncherData, data);
 
-  mWorkerState = eTerminated;
+  {
+    const auto lock = mSharedData.Lock();
+    lock->mWorkerState = eTerminated;
+  }
   data->mPendingOps.Clear();
 
   if (!mIPCActive) {
     return;
   }
 
   Unused << SendClose();
   mIPCActive = false;
@@ -430,27 +441,28 @@ void RemoteWorkerChild::ErrorPropagation
     return;
   }
 
   Unused << SendError(aValue);
 }
 
 void RemoteWorkerChild::CloseWorkerOnMainThread() {
   MOZ_ASSERT(NS_IsMainThread());
+  const auto lock = mSharedData.Lock();
 
-  if (mWorkerState == ePending) {
-    mWorkerState = ePendingTerminated;
+  if (lock->mWorkerState == ePending) {
+    lock->mWorkerState = ePendingTerminated;
     // Already released.
     return;
   }
 
   // The holder will be notified by this.
-  if (mWorkerState == eRunning) {
-    MOZ_RELEASE_ASSERT(mWorkerPrivate);
-    mWorkerPrivate->Cancel();
+  if (lock->mWorkerState == eRunning) {
+    MOZ_RELEASE_ASSERT(lock->mWorkerPrivate);
+    lock->mWorkerPrivate->Cancel();
   }
 }
 
 void RemoteWorkerChild::FlushReportsOnMainThread(
     nsIConsoleReportCollector* aReporter) {
   MOZ_ASSERT(NS_IsMainThread());
 
   bool reportErrorToBrowserConsole = true;
@@ -467,34 +479,42 @@ void RemoteWorkerChild::FlushReportsOnMa
     aReporter->FlushReportsToConsole(0);
     return;
   }
 
   aReporter->ClearConsoleReports();
 }
 
 IPCResult RemoteWorkerChild::RecvExecOp(const RemoteWorkerOp& aOp) {
+  const auto lock = mSharedData.Lock();
+  return ExecuteOperation(aOp, lock);
+}
+
+template <typename T>
+IPCResult RemoteWorkerChild::ExecuteOperation(const RemoteWorkerOp& aOp,
+                                              const T& aLock) {
   MOZ_ACCESS_THREAD_BOUND(mLauncherData, data);
 
   if (!mIPCActive) {
     return IPC_OK();
   }
 
   // The worker is not ready yet.
-  if (mWorkerState == ePending) {
+  if (aLock->mWorkerState == ePending) {
     data->mPendingOps.AppendElement(aOp);
     return IPC_OK();
   }
 
-  if (mWorkerState == eTerminated || mWorkerState == ePendingTerminated) {
+  if (aLock->mWorkerState == eTerminated ||
+      aLock->mWorkerState == ePendingTerminated) {
     // No op.
     return IPC_OK();
   }
 
-  MOZ_ASSERT(mWorkerState == eRunning);
+  MOZ_ASSERT(aLock->mWorkerState == eRunning);
 
   // Main-thread operations
   if (aOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp ||
       aOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp ||
       aOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp ||
       aOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp ||
       aOp.type() == RemoteWorkerOp::TRemoteWorkerTerminateOp ||
       aOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp ||
@@ -509,58 +529,62 @@ IPCResult RemoteWorkerChild::RecvExecOp(
     target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
     return IPC_OK();
   }
 
   if (aOp.type() == RemoteWorkerOp::TRemoteWorkerPortIdentifierOp) {
     const RemoteWorkerPortIdentifierOp& op =
         aOp.get_RemoteWorkerPortIdentifierOp();
     RefPtr<MessagePortIdentifierRunnable> runnable =
-        new MessagePortIdentifierRunnable(mWorkerPrivate, this,
+        new MessagePortIdentifierRunnable(aLock->mWorkerPrivate, this,
                                           op.portIdentifier());
     if (NS_WARN_IF(!runnable->Dispatch())) {
       ErrorPropagation(NS_ERROR_FAILURE);
     }
     return IPC_OK();
   }
 
   MOZ_CRASH("Unknown operation.");
 
   return IPC_OK();
 }
 
 void RemoteWorkerChild::RecvExecOpOnMainThread(const RemoteWorkerOp& aOp) {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp) {
-    if (mWorkerPrivate) {
-      mWorkerPrivate->ParentWindowPaused();
-    }
-    return;
-  }
+  {
+    const auto lock = mSharedData.Lock();
 
-  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp) {
-    if (mWorkerPrivate) {
-      mWorkerPrivate->ParentWindowResumed();
+    if (aOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp) {
+      if (lock->mWorkerPrivate) {
+        lock->mWorkerPrivate->ParentWindowPaused();
+      }
+      return;
     }
-    return;
-  }
 
-  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp) {
-    if (mWorkerPrivate) {
-      mWorkerPrivate->Freeze(nullptr);
+    if (aOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp) {
+      if (lock->mWorkerPrivate) {
+        lock->mWorkerPrivate->ParentWindowResumed();
+      }
+      return;
     }
-    return;
-  }
 
-  if (aOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp) {
-    if (mWorkerPrivate) {
-      mWorkerPrivate->Thaw(nullptr);
+    if (aOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp) {
+      if (lock->mWorkerPrivate) {
+        lock->mWorkerPrivate->Freeze(nullptr);
+      }
+      return;
     }
-    return;
+
+    if (aOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp) {
+      if (lock->mWorkerPrivate) {
+        lock->mWorkerPrivate->Thaw(nullptr);
+      }
+      return;
+    }
   }
 
   if (aOp.type() == RemoteWorkerOp::TRemoteWorkerTerminateOp) {
     CloseWorkerOnMainThread();
     return;
   }
 
   if (aOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp) {
@@ -592,36 +616,37 @@ void RemoteWorkerChild::CreationSucceede
 
   RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
 }
 
 void RemoteWorkerChild::CreationSucceeded() {
   MOZ_ACCESS_THREAD_BOUND(mLauncherData, data);
 
   // The worker is created but we need to terminate it already.
-  if (mWorkerState == ePendingTerminated) {
+  const auto lock = mSharedData.Lock();
+  if (lock->mWorkerState == ePendingTerminated) {
     RefPtr<RemoteWorkerChild> self = this;
     nsCOMPtr<nsIRunnable> r =
         NS_NewRunnableFunction("RemoteWorkerChild::CreationSucceeded",
                                [self]() { self->CloseWorkerOnMainThread(); });
 
     nsCOMPtr<nsIEventTarget> target =
         SystemGroup::EventTargetFor(TaskCategory::Other);
     target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
     return;
   }
 
-  mWorkerState = eRunning;
+  lock->mWorkerState = eRunning;
 
   if (!mIPCActive) {
     return;
   }
 
   for (const RemoteWorkerOp& op : data->mPendingOps) {
-    RecvExecOp(op);
+    ExecuteOperation(op, lock);
   }
 
   data->mPendingOps.Clear();
 
   Unused << SendCreated(true);
 }
 
 void RemoteWorkerChild::CreationFailedOnAnyThread() {
@@ -631,17 +656,18 @@ void RemoteWorkerChild::CreationFailedOn
                              [self]() { self->CreationFailed(); });
 
   RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
 }
 
 void RemoteWorkerChild::CreationFailed() {
   MOZ_ACCESS_THREAD_BOUND(mLauncherData, data);
 
-  mWorkerState = eTerminated;
+  const auto lock = mSharedData.Lock();
+  lock->mWorkerState = eTerminated;
   data->mPendingOps.Clear();
 
   if (!mIPCActive) {
     return;
   }
 
   Unused << SendCreated(false);
 }
--- a/dom/workers/remoteworkers/RemoteWorkerChild.h
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.h
@@ -3,16 +3,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/. */
 
 #ifndef mozilla_dom_RemoteWorkerChild_h
 #define mozilla_dom_RemoteWorkerChild_h
 
 #include "mozilla/dom/PRemoteWorkerChild.h"
+#include "mozilla/DataMutex.h"
 #include "mozilla/ThreadBound.h"
 #include "mozilla/UniquePtr.h"
 #include "nsISupportsImpl.h"
 
 class nsIConsoleReportCollector;
 
 namespace mozilla {
 namespace dom {
@@ -51,16 +52,23 @@ class RemoteWorkerChild final : public P
   class InitializeWorkerRunnable;
 
   ~RemoteWorkerChild();
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvExecOp(const RemoteWorkerOp& aOp);
 
+  // This member is a function template because DataMutex<SharedData>::AutoLock
+  // is private, yet it must be passed by const reference into ExecuteOperation.
+  // There should only be one instantiation of this template.
+  template <typename T>
+  mozilla::ipc::IPCResult ExecuteOperation(const RemoteWorkerOp&,
+                                           const T& aLock);
+
   void RecvExecOpOnMainThread(const RemoteWorkerOp& aOp);
 
   nsresult ExecWorkerOnMainThread(const RemoteWorkerData& aData);
 
   void ErrorPropagation(const ErrorValue& aValue);
 
   void ErrorPropagationDispatch(nsresult aError);
 
@@ -72,17 +80,16 @@ class RemoteWorkerChild final : public P
 
   void CreationFailed();
 
   void WorkerTerminated();
 
   // Touched on main-thread only.
   nsTArray<uint64_t> mWindowIDs;
 
-  RefPtr<WorkerPrivate> mWorkerPrivate;
   RefPtr<WeakWorkerRef> mWorkerRef;
   bool mIPCActive;
 
   enum WorkerState {
     // CreationSucceeded/CreationFailed not called yet.
     ePending,
 
     // The worker is not created yet, but we want to terminate as soon as
@@ -91,18 +98,24 @@ class RemoteWorkerChild final : public P
 
     // Worker up and running.
     eRunning,
 
     // Worker terminated.
     eTerminated,
   };
 
-  // Touched only on the owning thread (Worker Launcher).
-  WorkerState mWorkerState;
+  struct SharedData {
+    SharedData();
+
+    RefPtr<WorkerPrivate> mWorkerPrivate;
+    WorkerState mWorkerState;
+  };
+
+  DataMutex<SharedData> mSharedData;
 
   // Touched only on the owning thread (Worker Launcher).
   struct LauncherBoundData {
     nsTArray<RemoteWorkerOp> mPendingOps;
   };
 
   ThreadBound<LauncherBoundData> mLauncherData;
 };
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1421,16 +1421,20 @@ void gfxWindowsPlatform::RecordContentDe
   if (!XRE_IsContentProcess()) {
     return;
   }
   Telemetry::Accumulate(Telemetry::GFX_CONTENT_FAILED_TO_ACQUIRE_DEVICE,
                         uint32_t(aDevice));
 }
 
 void gfxWindowsPlatform::RecordStartupTelemetry() {
+  if (!XRE_IsParentProcess()) {
+    return;
+  }
+
   DeviceManagerDx* dx = DeviceManagerDx::Get();
   nsTArray<DXGI_OUTPUT_DESC1> outputs = dx->EnumerateOutputs();
 
   uint32_t allSupportedColorSpaces = 0;
   for (auto& output : outputs) {
     uint32_t colorSpace = 1 << output.ColorSpace;
     allSupportedColorSpaces |= colorSpace;
   }
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1082,25 +1082,26 @@ void nsFrame::DidSetComputedStyle(Comput
 
   Document* doc = PresContext()->Document();
   ImageLoader* imageLoader = doc->StyleImageLoader();
   // Continuing text frame doesn't initialize its continuation pointer before
   // reaching here for the first time, so we have to exclude text frames. This
   // doesn't affect correctness because text can't match selectors.
   //
   // FIXME(emilio): We should consider fixing that.
-  const bool isNonTextFirstContinuation =
-      !IsTextFrame() && !GetPrevContinuation();
-  if (isNonTextFirstContinuation) {
+  //
+  // TODO(emilio): Can we avoid doing some / all of the image stuff when
+  // isNonTextFirstContinuation is false? We should consider doing this just for
+  // primary frames and pseudos, but the first-line reparenting code makes it
+  // all bad, should get around to bug 1465474 eventually :(
+  const bool isNonText = !IsTextFrame();
+  if (isNonText) {
     mComputedStyle->StartImageLoads(*doc);
   }
 
-  // TODO(emilio): Can we avoid doing some / all of this when
-  // isNonTextFirstContinuation is false? We should consider doing this just for
-  // primary frames and pseudos.
   const nsStyleImageLayers* oldLayers =
       aOldComputedStyle ? &aOldComputedStyle->StyleBackground()->mImage
                         : nullptr;
   const nsStyleImageLayers* newLayers = &StyleBackground()->mImage;
   AddAndRemoveImageAssociations(*imageLoader, this, oldLayers, newLayers);
 
   oldLayers =
       aOldComputedStyle ? &aOldComputedStyle->StyleSVGReset()->mMask : nullptr;
@@ -1223,16 +1224,17 @@ void nsFrame::DidSetComputedStyle(Comput
     if (newShapeImage) {
       imageLoader->AssociateRequestToFrame(
           newShapeImage, this, ImageLoader::REQUEST_REQUIRES_REFLOW);
     }
   }
 
   // SVGObserverUtils::GetEffectProperties() asserts that we only invoke it with
   // the first continuation so we need to check that in advance.
+  const bool isNonTextFirstContinuation = isNonText && !GetPrevContinuation();
   if (isNonTextFirstContinuation) {
     // Kick off loading of external SVG resources referenced from properties if
     // any. This currently includes filter, clip-path, and mask.
     SVGObserverUtils::InitiateResourceDocLoads(this);
   }
 
   // If the page contains markup that overrides text direction, and
   // does not contain any characters that would activate the Unicode
--- a/layout/style/ServoCSSRuleList.cpp
+++ b/layout/style/ServoCSSRuleList.cpp
@@ -152,16 +152,22 @@ void ServoCSSRuleList::DropParentRuleRef
 
 nsresult ServoCSSRuleList::InsertRule(const nsAString& aRule, uint32_t aIndex) {
   MOZ_ASSERT(mStyleSheet,
              "Caller must ensure that "
              "the list is not unlinked from stylesheet");
   NS_ConvertUTF16toUTF8 rule(aRule);
   bool nested = !!mParentRule;
   css::Loader* loader = nullptr;
+
+  // TODO(emilio, bug 1535456): Should probably always be able to get a handle
+  // to some loader if we're parsing an @import rule, but which one?
+  //
+  // StyleSheet::ReparseSheet just mints a new loader, but that'd be wrong in
+  // this case I think, since such a load will bypass CSP checks.
   if (Document* doc = mStyleSheet->GetAssociatedDocument()) {
     loader = doc->CSSLoader();
   }
   uint16_t type;
   nsresult rv =
       Servo_CssRules_InsertRule(mRawRules, mStyleSheet->RawContents(), &rule,
                                 aIndex, nested, loader, mStyleSheet, &type);
   if (NS_FAILED(rv)) {
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1533783.html
@@ -0,0 +1,10 @@
+<script>
+  function start() {
+    const style = document.createElement('style')
+    document.head.appendChild(style)
+    const sheet_1 = style.sheet
+    document.head.appendChild(style)
+    sheet_1.insertRule('@import url()', 0)
+  }
+  document.addEventListener('DOMContentLoaded', start)
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/1533891.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+    <style>
+        * {
+            border-image-source: url(data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7);
+        }
+        pre::first-line { }
+    </style>
+    <head>
+<body>
+<pre><data>]j% BAVxE</command>
+</body>
+</html>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -293,8 +293,10 @@ load 1469076.html
 load 1475003.html
 load 1479681.html
 load 1488817.html
 load 1490012.html
 load 1502893.html
 load 1509989.html
 load 1514086.html
 pref(layout.css.moz-binding.content.enabled,false) load 1517319.html
+load 1533891.html
+load 1533783.html
--- a/mobile/android/app/src/main/res/xml/search_widget_info.xml
+++ b/mobile/android/app/src/main/res/xml/search_widget_info.xml
@@ -1,18 +1,16 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <!-- 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/. -->
 
 <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
-    android:configure="org.mozilla.gecko.search.SearchWidgetConfigurationActivity"
     android:initialLayout="@layout/widget_search_default_col_layout"
     android:minWidth="360dp"
     android:minHeight="40dp"
     android:minResizeWidth="64dp"
     android:minResizeHeight="40dp"
     android:previewImage="@drawable/search_widget_preview"
     android:resizeMode="horizontal">
 
 </appwidget-provider>
-
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
@@ -111,16 +111,17 @@ public final class GeckoLoader {
 
                 prefsEnv.append(");\n");
             }
 
             putenv(prefsEnv.toString());
         }
     }
 
+    @SuppressWarnings("deprecation") // for Build.CPU_ABI
     public synchronized static void setupGeckoEnvironment(final Context context,
                                                           final String profilePath,
                                                           final Collection<String> env,
                                                           final Map<String, Object> prefs) {
         for (final String e : env) {
             putenv(e);
         }
 
@@ -171,16 +172,17 @@ public final class GeckoLoader {
 
         final Class<?> crashHandler = GeckoAppShell.getCrashHandlerService();
         if (crashHandler != null) {
             putenv("MOZ_ANDROID_CRASH_HANDLER=" +
                     context.getPackageName() + "/" + crashHandler.getName());
         }
 
         putenv("MOZ_ANDROID_DEVICE_SDK_VERSION=" + Build.VERSION.SDK_INT);
+        putenv("MOZ_ANDROID_CPU_ABI=" + Build.CPU_ABI);
 
         setupInitialPrefs(prefs);
 
         // env from extras could have reset out linker flags; set them again.
         loadLibsSetupLocked(context);
     }
 
     private static void loadLibsSetupLocked(Context context) {
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -4413,28 +4413,44 @@ float MOZ_MAYBE_UNUSED GetPref<float>(co
   // - $app/defaults/preferences/*.js
   //
   // When `$app == $gre`, we additionally load, in the omni.jar case:
   // - jar:$gre/omni.jar!/defaults/preferences/*.js
   //
   // Thus, in the omni.jar case, we always load app-specific default
   // preferences from omni.jar, whether or not `$app == $gre`.
 
-  nsresult rv;
+  nsresult rv = NS_ERROR_FAILURE;
   nsZipFind* findPtr;
   nsAutoPtr<nsZipFind> find;
   nsTArray<nsCString> prefEntries;
   const char* entryName;
   uint16_t entryNameLen;
 
   RefPtr<nsZipArchive> jarReader =
       mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
   if (jarReader) {
+#ifdef MOZ_WIDGET_ANDROID
+    // Try to load an architecture-specific greprefs.js first. This will be
+    // present in FAT AAR builds of GeckoView on Android.
+    const char* abi = getenv("MOZ_ANDROID_CPU_ABI");
+    if (abi) {
+      nsAutoCString path;
+      path.AppendPrintf("%s/greprefs.js", abi);
+      rv = pref_ReadPrefFromJar(jarReader, path.get());
+    }
+
+    if (NS_FAILED(rv)) {
+      // Fallback to toplevel greprefs.js if arch-specific load fails.
+      rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
+    }
+#else
     // Load jar:$gre/omni.jar!/greprefs.js.
     rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
+#endif
     NS_ENSURE_SUCCESS(rv, Err("pref_ReadPrefFromJar() failed"));
 
     // Load jar:$gre/omni.jar!/defaults/pref/*.js.
     rv = jarReader->FindInit("defaults/pref/*.js$", &findPtr);
     NS_ENSURE_SUCCESS(rv, Err("jarReader->FindInit() failed"));
 
     find = findPtr;
     while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4415,131 +4415,159 @@ pref("print.print_in_color", true);
 
 // fontconfig doesn't support emoji yet
 // https://lists.freedesktop.org/archives/fontconfig/2016-October/005842.html
 pref("font.name-list.emoji", "Twemoji Mozilla");
 
 pref("font.name-list.serif.ar", "serif");
 pref("font.name-list.sans-serif.ar", "sans-serif");
 pref("font.name-list.monospace.ar", "monospace");
+pref("font.name-list.cursive.ar", "cursive");
 pref("font.size.fixed.ar", 12);
 
 pref("font.name-list.serif.el", "serif");
 pref("font.name-list.sans-serif.el", "sans-serif");
 pref("font.name-list.monospace.el", "monospace");
+pref("font.name-list.cursive.el", "cursive");
 pref("font.size.fixed.el", 12);
 
 pref("font.name-list.serif.he", "serif");
 pref("font.name-list.sans-serif.he", "sans-serif");
 pref("font.name-list.monospace.he", "monospace");
+pref("font.name-list.cursive.he", "cursive");
 pref("font.size.fixed.he", 12);
 
 pref("font.name-list.serif.ja", "serif");
 pref("font.name-list.sans-serif.ja", "sans-serif");
 pref("font.name-list.monospace.ja", "monospace");
+pref("font.name-list.cursive.ja", "cursive");
 
 pref("font.name-list.serif.ko", "serif");
 pref("font.name-list.sans-serif.ko", "sans-serif");
 pref("font.name-list.monospace.ko", "monospace");
+pref("font.name-list.cursive.ko", "cursive");
 
 pref("font.name-list.serif.th", "serif");
 pref("font.name-list.sans-serif.th", "sans-serif");
 pref("font.name-list.monospace.th", "monospace");
+pref("font.name-list.cursive.th", "cursive");
 pref("font.minimum-size.th", 13);
 
 pref("font.name-list.serif.x-armn", "serif");
 pref("font.name-list.sans-serif.x-armn", "sans-serif");
 pref("font.name-list.monospace.x-armn", "monospace");
+pref("font.name-list.cursive.x-armn", "cursive");
 
 pref("font.name-list.serif.x-beng", "serif");
 pref("font.name-list.sans-serif.x-beng", "sans-serif");
 pref("font.name-list.monospace.x-beng", "monospace");
+pref("font.name-list.cursive.x-beng", "cursive");
 
 pref("font.name-list.serif.x-cans", "serif");
 pref("font.name-list.sans-serif.x-cans", "sans-serif");
 pref("font.name-list.monospace.x-cans", "monospace");
+pref("font.name-list.cursive.x-cans", "cursive");
 
 pref("font.name-list.serif.x-cyrillic", "serif");
 pref("font.name-list.sans-serif.x-cyrillic", "sans-serif");
 pref("font.name-list.monospace.x-cyrillic", "monospace");
+pref("font.name-list.cursive.x-cyrillic", "cursive");
 pref("font.size.fixed.x-cyrillic", 12);
 
 pref("font.name-list.serif.x-devanagari", "serif");
 pref("font.name-list.sans-serif.x-devanagari", "sans-serif");
 pref("font.name-list.monospace.x-devanagari", "monospace");
+pref("font.name-list.cursive.x-devanagari", "cursive");
 
 pref("font.name-list.serif.x-ethi", "serif");
 pref("font.name-list.sans-serif.x-ethi", "sans-serif");
 pref("font.name-list.monospace.x-ethi", "monospace");
+pref("font.name-list.cursive.x-ethi", "cursive");
 
 pref("font.name-list.serif.x-geor", "serif");
 pref("font.name-list.sans-serif.x-geor", "sans-serif");
 pref("font.name-list.monospace.x-geor", "monospace");
+pref("font.name-list.cursive.x-geor", "cursive");
 
 pref("font.name-list.serif.x-gujr", "serif");
 pref("font.name-list.sans-serif.x-gujr", "sans-serif");
 pref("font.name-list.monospace.x-gujr", "monospace");
+pref("font.name-list.cursive.x-gujr", "cursive");
 
 pref("font.name-list.serif.x-guru", "serif");
 pref("font.name-list.sans-serif.x-guru", "sans-serif");
 pref("font.name-list.monospace.x-guru", "monospace");
+pref("font.name-list.cursive.x-guru", "cursive");
 
 pref("font.name-list.serif.x-khmr", "serif");
 pref("font.name-list.sans-serif.x-khmr", "sans-serif");
 pref("font.name-list.monospace.x-khmr", "monospace");
+pref("font.name-list.cursive.x-khmr", "cursive");
 
 pref("font.name-list.serif.x-knda", "serif");
 pref("font.name-list.sans-serif.x-knda", "sans-serif");
 pref("font.name-list.monospace.x-knda", "monospace");
+pref("font.name-list.cursive.x-knda", "cursive");
 
 pref("font.name-list.serif.x-mlym", "serif");
 pref("font.name-list.sans-serif.x-mlym", "sans-serif");
 pref("font.name-list.monospace.x-mlym", "monospace");
+pref("font.name-list.cursive.x-mlym", "cursive");
 
 pref("font.name-list.serif.x-orya", "serif");
 pref("font.name-list.sans-serif.x-orya", "sans-serif");
 pref("font.name-list.monospace.x-orya", "monospace");
+pref("font.name-list.cursive.x-orya", "cursive");
 
 pref("font.name-list.serif.x-sinh", "serif");
 pref("font.name-list.sans-serif.x-sinh", "sans-serif");
 pref("font.name-list.monospace.x-sinh", "monospace");
+pref("font.name-list.cursive.x-sinh", "cursive");
 
 pref("font.name-list.serif.x-tamil", "serif");
 pref("font.name-list.sans-serif.x-tamil", "sans-serif");
 pref("font.name-list.monospace.x-tamil", "monospace");
+pref("font.name-list.cursive.x-tamil", "cursive");
 
 pref("font.name-list.serif.x-telu", "serif");
 pref("font.name-list.sans-serif.x-telu", "sans-serif");
 pref("font.name-list.monospace.x-telu", "monospace");
+pref("font.name-list.cursive.x-telu", "cursive");
 
 pref("font.name-list.serif.x-tibt", "serif");
 pref("font.name-list.sans-serif.x-tibt", "sans-serif");
 pref("font.name-list.monospace.x-tibt", "monospace");
+pref("font.name-list.cursive.x-tibt", "cursive");
 
 pref("font.name-list.serif.x-unicode", "serif");
 pref("font.name-list.sans-serif.x-unicode", "sans-serif");
 pref("font.name-list.monospace.x-unicode", "monospace");
+pref("font.name-list.cursive.x-unicode", "cursive");
 pref("font.size.fixed.x-unicode", 12);
 
 pref("font.name-list.serif.x-western", "serif");
 pref("font.name-list.sans-serif.x-western", "sans-serif");
 pref("font.name-list.monospace.x-western", "monospace");
+pref("font.name-list.cursive.x-western", "cursive");
 pref("font.size.fixed.x-western", 12);
 
 pref("font.name-list.serif.zh-CN", "serif");
 pref("font.name-list.sans-serif.zh-CN", "sans-serif");
 pref("font.name-list.monospace.zh-CN", "monospace");
+pref("font.name-list.cursive.zh-CN", "cursive");
 
 pref("font.name-list.serif.zh-HK", "serif");
 pref("font.name-list.sans-serif.zh-HK", "sans-serif");
 pref("font.name-list.monospace.zh-HK", "monospace");
+pref("font.name-list.cursive.zh-HK", "cursive");
 
 pref("font.name-list.serif.zh-TW", "serif");
 pref("font.name-list.sans-serif.zh-TW", "sans-serif");
 pref("font.name-list.monospace.zh-TW", "monospace");
+pref("font.name-list.cursive.zh-TW", "cursive");
 
 /* PostScript print module prefs */
 // pref("print.postscript.enabled",      true);
 
 // On GTK2 platform, we should use topmost window level for the default window
 // level of <panel> element of XUL. GTK2 has only two window types. One is
 // normal top level window, other is popup window. The popup window is always
 // topmost window level, therefore, we are using normal top level window for
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -7362,17 +7362,17 @@ nsresult nsHttpChannel::ProcessCrossOrig
   } else {
     mLoadInfo->GetFrameBrowsingContext(getter_AddRefs(ctx));
   }
 
   if (!ctx) {
     return NS_OK;
   }
 
-  nsILoadInfo::CrossOriginPolicy documentPolicy = ctx->CrossOriginPolicy();
+  nsILoadInfo::CrossOriginPolicy documentPolicy = ctx->GetCrossOriginPolicy();
   nsILoadInfo::CrossOriginPolicy resultPolicy =
       nsILoadInfo::CROSS_ORIGIN_POLICY_NULL;
   rv = GetResponseCrossOriginPolicy(&resultPolicy);
   if (NS_FAILED(rv)) {
     return NS_OK;
   }
 
   ctx->SetCrossOriginPolicy(resultPolicy);
--- a/netwerk/protocol/http/nsHttpConnectionInfo.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.cpp
@@ -225,18 +225,18 @@ void nsHttpConnectionInfo::BuildHashKey(
 
 void nsHttpConnectionInfo::SetOriginServer(const nsACString &host,
                                            int32_t port) {
   mOrigin = host;
   mOriginPort = port == -1 ? DefaultPort() : port;
   BuildHashKey();
 }
 
-nsHttpConnectionInfo *nsHttpConnectionInfo::Clone() const {
-  nsHttpConnectionInfo *clone;
+already_AddRefed<nsHttpConnectionInfo> nsHttpConnectionInfo::Clone() const {
+  RefPtr<nsHttpConnectionInfo> clone;
   if (mRoutedHost.IsEmpty()) {
     clone =
         new nsHttpConnectionInfo(mOrigin, mOriginPort, mNPNToken, mUsername,
                                  mProxyInfo, mOriginAttributes, mEndToEndSSL);
   } else {
     MOZ_ASSERT(mEndToEndSSL);
     clone = new nsHttpConnectionInfo(mOrigin, mOriginPort, mNPNToken, mUsername,
                                      mProxyInfo, mOriginAttributes, mRoutedHost,
@@ -251,22 +251,23 @@ nsHttpConnectionInfo *nsHttpConnectionIn
   clone->SetBeConservative(GetBeConservative());
   clone->SetTlsFlags(GetTlsFlags());
   clone->SetTrrUsed(GetTrrUsed());
   clone->SetTrrDisabled(GetTrrDisabled());
   clone->SetIPv4Disabled(GetIPv4Disabled());
   clone->SetIPv6Disabled(GetIPv6Disabled());
   MOZ_ASSERT(clone->Equals(this));
 
-  return clone;
+  return clone.forget();
 }
 
 void nsHttpConnectionInfo::CloneAsDirectRoute(nsHttpConnectionInfo **outCI) {
   if (mRoutedHost.IsEmpty()) {
-    *outCI = Clone();
+    RefPtr<nsHttpConnectionInfo> clone = Clone();
+    clone.forget(outCI);
     return;
   }
 
   RefPtr<nsHttpConnectionInfo> clone =
       new nsHttpConnectionInfo(mOrigin, mOriginPort, EmptyCString(), mUsername,
                                mProxyInfo, mOriginAttributes, mEndToEndSSL);
   // Make sure the anonymous, insecure-scheme, and private flags are transferred
   clone->SetAnonymous(GetAnonymous());
--- a/netwerk/protocol/http/nsHttpConnectionInfo.h
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.h
@@ -8,16 +8,17 @@
 #define nsHttpConnectionInfo_h__
 
 #include "nsHttp.h"
 #include "nsProxyInfo.h"
 #include "nsCOMPtr.h"
 #include "nsStringFwd.h"
 #include "mozilla/Logging.h"
 #include "mozilla/BasePrincipal.h"
+#include "mozilla/AlreadyAddRefed.h"
 #include "ARefBase.h"
 
 //-----------------------------------------------------------------------------
 // nsHttpConnectionInfo - holds the properties of a connection
 //-----------------------------------------------------------------------------
 
 // http:// uris through a proxy will all share the same CI, because they can
 // all use the same connection. (modulo pb and anonymous flags). They just use
@@ -65,17 +66,17 @@ class nsHttpConnectionInfo final : publi
   const char *Origin() const { return mOrigin.get(); }
   int32_t OriginPort() const { return mOriginPort; }
 
   const nsCString &GetRoutedHost() const { return mRoutedHost; }
   const char *RoutedHost() const { return mRoutedHost.get(); }
   int32_t RoutedPort() const { return mRoutedPort; }
 
   // OK to treat these as an infalible allocation
-  nsHttpConnectionInfo *Clone() const;
+  already_AddRefed<nsHttpConnectionInfo> Clone() const;
   void CloneAsDirectRoute(nsHttpConnectionInfo **outParam);
   MOZ_MUST_USE nsresult CreateWildCard(nsHttpConnectionInfo **outParam);
 
   const char *ProxyHost() const {
     return mProxyInfo ? mProxyInfo->Host().get() : nullptr;
   }
   int32_t ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
   const char *ProxyType() const {
--- a/servo/components/style/stylesheets/rule_parser.rs
+++ b/servo/components/style/stylesheets/rule_parser.rs
@@ -184,16 +184,23 @@ impl<'a, 'i> AtRuleParser<'i> for TopLev
         input: &mut Parser<'i, 't>,
     ) -> Result<AtRuleType<AtRuleNonBlockPrelude, AtRuleBlockPrelude>, ParseError<'i>> {
         match_ignore_ascii_case! { &*name,
             "import" => {
                 if !self.check_state(State::Imports) {
                     return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
                 }
 
+                // FIXME(emilio): We should always be able to have a loader
+                // around! See bug 1533783.
+                if self.loader.is_none() {
+                    error!("Saw @import rule, but no way to trigger the load");
+                    return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
+                }
+
                 let url_string = input.expect_url_or_string()?.as_ref().to_owned();
                 let url = CssUrl::parse_from_string(url_string, &self.context);
 
                 let media = MediaList::parse(&self.context, input);
                 let media = Arc::new(self.shared_lock.wrap(media));
 
                 let prelude = AtRuleNonBlockPrelude::Import(url, media);
                 return Ok(AtRuleType::WithoutBlock(prelude));
--- a/taskcluster/ci/toolchain/clang-tidy.yml
+++ b/taskcluster/ci/toolchain/clang-tidy.yml
@@ -53,35 +53,16 @@ macosx64-clang-tidy:
             - 'build/build-clang/clang-tidy-macosx64.json'
             - 'taskcluster/scripts/misc/tooltool-download.sh'
     toolchains:
         - linux64-cctools-port
         - linux64-clang-7
         - linux64-gcc-4.9
         - linux64-node
 
-win32-clang-tidy:
-    description: "Clang-tidy toolchain build"
-    index:
-        job-name: win32-clang-tidy
-    treeherder:
-        symbol: TW32(clang-tidy)
-        tier: 2
-    worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
-    worker:
-        max-run-time: 7200
-        env:
-            TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/win32/build-clang-cl.manifest"
-    run:
-        script: build-clang-tidy32-windows.sh
-        resources:
-            - 'build/build-clang/clang-tidy-win32.json'
-            - 'taskcluster/scripts/misc/build-clang-windows-helper32.sh'
-        toolchain-artifact: public/build/clang-tidy.tar.bz2
-
 win64-clang-tidy:
     description: "Clang-tidy toolchain build"
     index:
         job-name: win64-clang-tidy
     treeherder:
         symbol: TW64(clang-tidy)
         tier: 2
     worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
--- a/taskcluster/docs/parameters.rst
+++ b/taskcluster/docs/parameters.rst
@@ -40,17 +40,17 @@ Push Information
    the symbolic ref containing ``head_rev`` that should be pulled from
    ``head_repository``.
 
 ``owner``
    Email address indicating the person who made the push.  Note that this
    value may be forged and *must not* be relied on for authentication.
 
 ``message``
-   The commit message
+   The try syntax in the commit message, if any.
 
 ``pushlog_id``
    The ID from the ``hg.mozilla.org`` pushlog
 
 ``pushdate``
    The timestamp of the push to the repository that triggered this decision
    task.  Expressed as an integer seconds since the UNIX epoch.
 
@@ -60,16 +60,19 @@ Push Information
 ``build_date``
    The timestamp of the build date. Defaults to ``pushdate`` and falls back to present time of
    taskgraph invocation. Expressed as an integer seconds since the UNIX epoch.
 
 ``moz_build_date``
    A formatted timestamp of ``build_date``. Expressed as a string with the following
    format: %Y%m%d%H%M%S
 
+``tasks_for``
+   The ``tasks_for`` value used to generate the decision task.
+
 Tree Information
 ----------------
 
 ``project``
    Another name for what may otherwise be called tree or branch or
    repository.  This is the unqualified name, such as ``mozilla-central`` or
    ``cedar``.
 
--- a/taskcluster/mach_commands.py
+++ b/taskcluster/mach_commands.py
@@ -172,16 +172,18 @@ class MachCommands(MachCommandBase):
     @CommandArgument('--optimize-target-tasks',
                      type=strtobool,
                      nargs='?', const='true',
                      help='If specified, this indicates whether the target '
                           'tasks are eligible for optimization. Otherwise, '
                           'the default for the project is used.')
     @CommandArgument('--try-task-config-file',
                      help='path to try task configuration file')
+    @CommandArgument('--tasks-for',
+                     help='the tasks_for value used to generate this task')
     def taskgraph_decision(self, **options):
         """Run the decision task: generate a task graph and submit to
         TaskCluster.  This is only meant to be called within decision tasks,
         and requires a great many arguments.  Commands like `mach taskgraph
         optimized` are better suited to use on the command line, and can take
         the parameters file generated by a decision task.  """
 
         import taskgraph.decision
deleted file mode 100755
--- a/taskcluster/scripts/misc/build-clang-tidy32-windows.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-source build/src/taskcluster/scripts/misc/build-clang-windows-helper32.sh clang-tidy-win32.json
deleted file mode 100755
--- a/taskcluster/scripts/misc/build-clang-windows-helper32.sh
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/bin/bash
-
-set -x -e -v
-
-# This script is for building clang-cl on Windows.
-
-: TOOLTOOL_CACHE                ${TOOLTOOL_CACHE:=/builds/worker/tooltool-cache}
-export TOOLTOOL_CACHE
-
-TOOLTOOL_AUTH_FILE=/c/builds/relengapi.tok
-if [ ! -e ${TOOLTOOL_AUTH_FILE} ]; then
-    echo cannot find ${TOOLTOOL_AUTH_FILE}
-    exit 1
-fi
-
-./build/src/mach artifact toolchain -v --authentication-file="${TOOLTOOL_AUTH_FILE}" --tooltool-manifest "build/src/${TOOLTOOL_MANIFEST}"${TOOLTOOL_CACHE:+ --cache-dir ${TOOLTOOL_CACHE}}${MOZ_TOOLCHAINS:+ ${MOZ_TOOLCHAINS}}
-
-# Set up all the Visual Studio paths.
-MSVC_DIR=vs2017_15.8.4
-VSWINPATH="$(cd ${MSVC_DIR} && pwd)"
-
-echo vswinpath ${VSWINPATH}
-
-# LLVM_ENABLE_DIA_SDK is set if the directory "$ENV{VSINSTALLDIR}DIA SDK"
-# exists.
-export VSINSTALLDIR="${VSWINPATH}/"
-
-export WINDOWSSDKDIR="${VSWINPATH}/SDK"
-export WIN32_REDIST_DIR="${VSWINPATH}/VC/redist/x86/Microsoft.VC141.CRT"
-export WIN_UCRT_REDIST_DIR="${VSWINPATH}/SDK/Redist/ucrt/DLLs/x86"
-
-export PATH="${VSWINPATH}/VC/bin/Hostx64/x86:${VSWINPATH}/VC/bin/Hostx64/x64:${VSWINPATH}/SDK/bin/10.0.17134.0/x64:${VSWINPATH}/DIA SDK/bin:${PATH}"
-export PATH="${VSWINPATH}/VC/redist/x86/Microsoft.VC141.CRT:${VSWINPATH}/SDK/Redist/ucrt/DLLs/x86:${PATH}"
-
-export INCLUDE="${VSWINPATH}/VC/include:${VSWINPATH}/VC/atlmfc/include:${VSWINPATH}/SDK/Include/10.0.17134.0/ucrt:${VSWINPATH}/SDK/Include/10.0.17134.0/shared:${VSWINPATH}/SDK/Include/10.0.17134.0/um:${VSWINPATH}/SDK/Include/10.0.17134.0/winrt:${VSWINPATH}/DIA SDK/include"
-export LIB="${VSWINPATH}/VC/lib/x86:${VSWINPATH}/VC/atlmfc/lib/x86:${VSWINPATH}/SDK/Lib/10.0.17134.0/ucrt/x86:${VSWINPATH}/SDK/Lib/10.0.17134.0/um/x86:${VSWINPATH}/DIA SDK/lib"
-
-export PATH="$(cd svn && pwd)/bin:${PATH}"
-export PATH="$(cd cmake && pwd)/bin:${PATH}"
-export PATH="$(cd ninja && pwd)/bin:${PATH}"
-
-# We use |mach python| to set up a virtualenv automatically for us.  We create
-# a dummy mozconfig, because the default machinery for config.guess-choosing
-# of the objdir doesn't work very well.
-MOZCONFIG="$(pwd)/mozconfig"
-cat > ${MOZCONFIG} <<EOF
-mk_add_options MOZ_OBJDIR=$(pwd)/objdir
-EOF
-
-# gets a bit too verbose here
-set +x
-
-BUILD_CLANG_DIR=build/src/build/build-clang
-cd ${BUILD_CLANG_DIR}
-MOZCONFIG=${MOZCONFIG} ../../mach python ./build-clang.py -c ./${1}
-cd -
-
-set -x
-
-# Put a tarball in the artifacts dir
-UPLOAD_PATH=public/build
-mkdir -p ${UPLOAD_PATH}
-cp ${BUILD_CLANG_DIR}/clang*.tar.* ${UPLOAD_PATH}
--- a/taskcluster/taskgraph/decision.py
+++ b/taskcluster/taskgraph/decision.py
@@ -205,40 +205,42 @@ def get_decision_parameters(config, opti
         'head_rev',
         'head_ref',
         'project',
         'pushlog_id',
         'pushdate',
         'owner',
         'level',
         'target_tasks_method',
+        'tasks_for',
     ] if n in options}
 
     for n in (
         'comm_base_repository',
         'comm_head_repository',
         'comm_head_rev',
         'comm_head_ref',
     ):
         if n in options and options[n] is not None:
             parameters[n] = options[n]
 
+    commit_message = get_hg_commit_message(os.path.join(GECKO, product_dir))
+
     # Define default filter list, as most configurations shouldn't need
     # custom filters.
     parameters['filters'] = [
         'target_tasks_method',
     ]
     parameters['optimize_target_tasks'] = True
     parameters['existing_tasks'] = {}
     parameters['do_not_optimize'] = []
     parameters['build_number'] = 1
     parameters['version'] = get_version(product_dir)
     parameters['app_version'] = get_app_version(product_dir)
-    parameters['message'] = try_syntax_from_message(
-            get_hg_commit_message(os.path.join(GECKO, product_dir)))
+    parameters['message'] = try_syntax_from_message(commit_message)
     parameters['hg_branch'] = get_hg_revision_branch(GECKO, revision=parameters['head_rev'])
     parameters['next_version'] = None
     parameters['phabricator_diff'] = None
     parameters['release_type'] = ''
     parameters['release_eta'] = ''
     parameters['release_enable_partners'] = False
     parameters['release_partners'] = []
     parameters['release_partner_config'] = {}
@@ -270,16 +272,22 @@ def get_decision_parameters(config, opti
                        "PER_PROJECT_PARAMETERS in {} to customize behavior "
                        "for this project".format(project, __file__))
         parameters.update(PER_PROJECT_PARAMETERS['default'])
 
     # `target_tasks_method` has higher precedence than `project` parameters
     if options.get('target_tasks_method'):
         parameters['target_tasks_method'] = options['target_tasks_method']
 
+    # ..but can be overridden by the commit message: if it contains the special
+    # string "DONTBUILD" and this is an on-push decision task, then use the
+    # special 'nothing' target task method.
+    if 'DONTBUILD' in commit_message and options['tasks_for'] == 'hg-push':
+        parameters['target_tasks_method'] = 'nothing'
+
     # If the target method is nightly, we should build partials. This means
     # knowing what has been released previously.
     # An empty release_history is fine, it just means no partials will be built
     parameters.setdefault('release_history', dict())
     if 'nightly' in parameters.get('target_tasks_method', ''):
         parameters['release_history'] = populate_release_history('Firefox', project)
 
     if options.get('try_task_config_file'):
--- a/taskcluster/taskgraph/parameters.py
+++ b/taskcluster/taskgraph/parameters.py
@@ -41,17 +41,17 @@ def get_version(product_dir='browser'):
 
 def get_app_version(product_dir='browser'):
     app_version_path = os.path.join(GECKO, product_dir, 'config',
                                     'version.txt')
     return get_contents(app_version_path)
 
 
 # Please keep this list sorted and in sync with taskcluster/docs/parameters.rst
-# Parameters are of the form: {name: default}
+# Parameters are of the form: {name: default} or {name: lambda: default}
 PARAMETERS = {
     'app_version': get_app_version(),
     'base_repository': 'https://hg.mozilla.org/mozilla-unified',
     'build_date': lambda: int(time.time()),
     'build_number': 1,
     'do_not_optimize': [],
     'existing_tasks': {},
     'filters': ['target_tasks_method'],
@@ -76,16 +76,17 @@ PARAMETERS = {
     'release_partners': None,
     'release_partner_config': None,
     'release_partner_build_number': 1,
     'release_type': 'nightly',
     'release_product': None,
     'required_signoffs': [],
     'signoff_urls': {},
     'target_tasks_method': 'default',
+    'tasks_for': 'hg-push',
     'try_mode': None,
     'try_options': None,
     'try_task_config': None,
     'version': get_version(),
 }
 
 COMM_PARAMETERS = {
     'comm_base_repository': 'https://hg.mozilla.org/comm-central',
--- a/taskcluster/taskgraph/target_tasks.py
+++ b/taskcluster/taskgraph/target_tasks.py
@@ -677,8 +677,14 @@ def target_tasks_codereview(full_task_gr
 
         # Analyzer tasks
         if task.attributes.get('code-review') is True:
             return True
 
         return False
 
     return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
+
+
+@_target_task('nothing')
+def target_tasks_nothing(full_task_graph, parameters, graph_config):
+    """Select nothing, for DONTBUILD pushes"""
+    return []
--- a/taskcluster/taskgraph/test/test_decision.py
+++ b/taskcluster/taskgraph/test/test_decision.py
@@ -57,16 +57,17 @@ class TestGetDecisionParameters(unittest
             'head_repository': 'https://hg.mozilla.org/mozilla-central',
             'head_rev': 'abcd',
             'head_ref': 'ef01',
             'message': '',
             'project': 'mozilla-central',
             'pushlog_id': 143,
             'pushdate': 1503691511,
             'owner': 'nobody@mozilla.com',
+            'tasks_for': 'hg-push',
             'level': 3,
         }
 
     @patch('taskgraph.decision.get_hg_revision_branch')
     def test_simple_options(self, mock_get_hg_revision_branch):
         mock_get_hg_revision_branch.return_value = 'default'
         with MockedOpen({self.ttc_file: None}):
             params = decision.get_decision_parameters(FAKE_GRAPH_CONFIG, self.options)
--- a/testing/marionette/browser.js
+++ b/testing/marionette/browser.js
@@ -324,26 +324,22 @@ browser.Context = class {
 
         // Bug 1509380 - Missing focus/activate event when Firefox is not
         // the top-most application. As such wait for the next tick, and
         // manually focus the newly opened window.
         win.setTimeout(() => win.focus(), 0);
 
         await Promise.all([activated, focused, startup]);
 
-        logger.trace("Opening window is active window: " +
-            `${Services.focus.activeWindow == this.window}`);
-        if (!focus) {
-          // The new window shouldn't get focused. As such set the
-          // focus back to the currently selected window.
+        // The new window shouldn't get focused. As such set the
+        // focus back to the opening window if needed.
+        if (!focus && Services.focus.activeWindow != this.window) {
           activated = waitForEvent(this.window, "activate");
           focused = waitForEvent(this.window, "focus", {capture: true});
 
-          logger.trace("Setting focus back to opening window " +
-              `due to focus: ${focus}`);
           this.window.focus();
 
           await Promise.all([activated, focused]);
         }
 
         return win;
 
       default:
@@ -398,17 +394,18 @@ browser.Context = class {
    * Open a new tab in the currently selected chrome window.
    */
   async openTab(focus = false) {
     let tab = null;
     let tabOpened = waitForEvent(this.window, "TabOpen");
 
     switch (this.driver.appName) {
       case "fennec":
-        tab = this.tabBrowser.addTab(null, {selected: focus});
+        tab = this.tabBrowser.addTab(null);
+        this.tabBrowser.selectTab(focus ? tab : this.tab);
         break;
 
       case "firefox":
         this.window.BrowserOpenTab();
         tab = this.tabBrowser.selectedTab;
 
         // The new tab is always selected by default. If focus is not wanted,
         // the previously tab needs to be selected again.
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -1338,28 +1338,28 @@ class Marionette(object):
         ::
 
             alert = self.marionette.switch_to_alert()
             text = alert.text
             alert.accept()
         """
         return Alert(self)
 
-    def switch_to_window(self, window_id, focus=True):
+    def switch_to_window(self, handle, focus=True):
         """Switch to the specified window; subsequent commands will be
         directed at the new window.
 
-        :param window_id: The id or name of the window to switch to.
+        :param handle: The id or name of the window to switch to.
 
         :param focus: A boolean value which determins whether to focus
             the window that we just switched to.
         """
         self._send_message("WebDriver:SwitchToWindow",
-                           {"focus": focus, "name": window_id})
-        self.window = window_id
+                           {"focus": focus, "name": handle, "handle": handle})
+        self.window = handle
 
     def get_active_frame(self):
         """Returns an :class:`~marionette_driver.marionette.HTMLElement`
         representing the frame Marionette is currently acting on."""
         return self._send_message("WebDriver:GetActiveFrame",
                                   key="value")
 
     def switch_to_default_content(self):
--- a/toolkit/actors/PictureInPictureChild.jsm
+++ b/toolkit/actors/PictureInPictureChild.jsm
@@ -9,17 +9,19 @@ var EXPORTED_SYMBOLS = ["PictureInPictur
 const {ActorChild} = ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
 
 var gWeakVideo = null;
 
 class PictureInPictureChild extends ActorChild {
   handleEvent(event) {
     switch (event.type) {
       case "MozTogglePictureInPicture": {
-        this.togglePictureInPicture(event.target);
+        if (event.isTrusted) {
+          this.togglePictureInPicture(event.target);
+        }
         break;
       }
     }
   }
 
   togglePictureInPicture(video) {
     if (this.inPictureInPicture(video)) {
       this.closePictureInPicture(video);
--- a/toolkit/components/browser/nsWebBrowser.cpp
+++ b/toolkit/components/browser/nsWebBrowser.cpp
@@ -97,42 +97,31 @@ nsIWidget* nsWebBrowser::EnsureWidget() 
                     nullptr);
 
   return mInternalWidget;
 }
 
 /* static */
 already_AddRefed<nsWebBrowser> nsWebBrowser::Create(
     nsIWebBrowserChrome* aContainerWindow, nsIWidget* aParentWidget,
-    const OriginAttributes& aOriginAttributes, mozIDOMWindowProxy* aOpener,
-    int aItemType) {
-  RefPtr<nsWebBrowser> browser = new nsWebBrowser(aItemType);
+    const OriginAttributes& aOriginAttributes,
+    dom::BrowsingContext* aBrowsingContext) {
+  RefPtr<nsWebBrowser> browser = new nsWebBrowser(
+      aBrowsingContext->IsContent() ? typeContentWrapper : typeChromeWrapper);
 
   // nsWebBrowser::SetContainer also calls nsWebBrowser::EnsureDocShellTreeOwner
   NS_ENSURE_SUCCESS(browser->SetContainerWindow(aContainerWindow), nullptr);
   NS_ENSURE_SUCCESS(browser->SetParentWidget(aParentWidget), nullptr);
 
   nsCOMPtr<nsIWidget> docShellParentWidget = browser->EnsureWidget();
   if (NS_WARN_IF(!docShellParentWidget)) {
     return nullptr;
   }
 
-  // XXX(nika): Consider supporting creating nsWebBrowser for an existing
-  // BrowsingContext (e.g. during a X-process load).
-  using BrowsingContext = mozilla::dom::BrowsingContext;
-  RefPtr<BrowsingContext> openerContext =
-      aOpener ? nsPIDOMWindowOuter::From(aOpener)->GetBrowsingContext()
-              : nullptr;
-
-  RefPtr<BrowsingContext> browsingContext = BrowsingContext::Create(
-      /* aParent */ nullptr, openerContext, EmptyString(),
-      aItemType != typeChromeWrapper ? BrowsingContext::Type::Content
-                                     : BrowsingContext::Type::Chrome);
-
-  RefPtr<nsDocShell> docShell = nsDocShell::Create(browsingContext);
+  RefPtr<nsDocShell> docShell = nsDocShell::Create(aBrowsingContext);
   if (NS_WARN_IF(!docShell)) {
     return nullptr;
   }
   docShell->SetOriginAttributes(aOriginAttributes);
   browser->SetDocShell(docShell);
 
   // get the system default window background colour
   LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
--- a/toolkit/components/browser/nsWebBrowser.h
+++ b/toolkit/components/browser/nsWebBrowser.h
@@ -103,17 +103,17 @@ class nsWebBrowser final : public nsIWeb
 
   void SetAllowDNSPrefetch(bool aAllowPrefetch);
   void FocusActivate();
   void FocusDeactivate();
 
   static already_AddRefed<nsWebBrowser> Create(
       nsIWebBrowserChrome* aContainerWindow, nsIWidget* aParentWidget,
       const mozilla::OriginAttributes& aOriginAttributes,
-      mozIDOMWindowProxy* aOpener, int aItemType);
+      mozilla::dom::BrowsingContext* aBrowsingContext);
 
  protected:
   virtual ~nsWebBrowser();
   NS_IMETHOD InternalDestroy();
 
   // XXXbz why are these NS_IMETHOD?  They're not interface methods!
   NS_IMETHOD SetDocShell(nsIDocShell* aDocShell);
   NS_IMETHOD EnsureDocShellTreeOwner();
--- a/toolkit/components/extensions/test/mochitest/head_webrequest.js
+++ b/toolkit/components/extensions/test/mochitest/head_webrequest.js
@@ -234,17 +234,23 @@ function background(events) {
         browser.test.assertEq(expectedIp, details.ip, `correct ip for ${details.url}`);
       }
       if (expected.headers && expected.headers.response) {
         checkHeaders("response", expected, details);
       }
     },
     onErrorOccurred(expected, details, result) {
       if (expected.error) {
-        browser.test.assertEq(expected.error, details.error, "expected error message received in onErrorOccurred");
+        if (Array.isArray(expected.error)) {
+          browser.test.assertTrue(
+            expected.error.includes(details.error),
+            "expected error message received in onErrorOccurred");
+        } else {
+          browser.test.assertEq(expected.error, details.error, "expected error message received in onErrorOccurred");
+        }
       }
     },
   };
 
   function getListener(name) {
     return details => {
       let result = {};
       browser.test.log(`${name} ${details.requestId} ${details.url}`);
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html
@@ -373,17 +373,21 @@ add_task(async function test_webRequest_
     "dummy_page.html": {
       type: "sub_frame",
       status: 404,
     },
     "badrobot": {
       type: "sub_frame",
       status: 404,
       events: ["onBeforeRequest", "onBeforeSendHeaders", "onSendHeaders", "onErrorOccurred"],
-      error: "NS_ERROR_UNKNOWN_HOST",
+      // When an url's hostname fails to be resolved, an NS_ERROR_NET_ON_RESOLVED/RESOLVING
+      // onError event may be fired right before the NS_ERROR_UNKNOWN_HOST
+      // (See Bug 1516862 for a rationale).
+      optional_events: ["onErrorOccurred"],
+      error: ["NS_ERROR_UNKNOWN_HOST", "NS_ERROR_NET_ON_RESOLVED", "NS_ERROR_NET_ON_RESOLVING"],
     },
   };
   extension.sendMessage("set-expected", {expect, origin: location.href});
   await extension.awaitMessage("continue");
   addFrame("data:text/plain,webRequestTest");
   addFrame("data:text/plain,webRequestTest_bad");
   await extension.awaitMessage("cancelled");
   addFrame("redirection.sjs");
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -6094,27 +6094,27 @@
     "high": 10000,
     "n_buckets": 50,
     "description": "Firefox: Time taken from the point of closing a tab (with animation), to the browser element being removed from the DOM. (ms)."
   },
   "FX_TAB_CLOSE_TIME_NO_ANIM_MS": {
     "record_in_processes": ["main"],
     "alert_emails": ["mconley@mozilla.com", "hkirschner@mozilla.com"],
     "bug_numbers": [1340842],
-    "expires_in_version": "68",
+    "expires_in_version": "72",
     "kind": "exponential",
     "high": 10000,
     "n_buckets": 50,
     "description": "Firefox: Time taken from the point of closing a tab (without animation) to the browser element being removed from the DOM. (ms)."
   },
   "FX_TAB_CLOSE_PERMIT_UNLOAD_TIME_MS": {
     "record_in_processes": ["main"],
     "alert_emails": ["mconley@mozilla.com", "hkirschner@mozilla.com"],
     "bug_numbers": [1340842],
-    "expires_in_version": "68",
+    "expires_in_version": "72",
     "kind": "exponential",
     "high": 10000,
     "n_buckets": 50,
     "description": "Firefox: Time taken to run permitUnload on a browser during tab close to see whether or not we're allowed to close the tab (ms)."
   },
   "FX_REFRESH_DRIVER_CHROME_FRAME_DELAY_MS": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["perf-telemetry-alerts@mozilla.com", "gfx-telemetry-alerts@mozilla.com", "rhunt@mozilla.com"],
--- a/toolkit/modules/ActorManagerParent.jsm
+++ b/toolkit/modules/ActorManagerParent.jsm
@@ -348,17 +348,17 @@ let ACTORS = {
   },
 };
 
 if (AppConstants.NIGHTLY_BUILD) {
   ACTORS.PictureInPicture = {
     child: {
       module: "resource://gre/actors/PictureInPictureChild.jsm",
       events: {
-        "MozTogglePictureInPicture": {capture: true, wantUntrusted: true},
+        "MozTogglePictureInPicture": {capture: true},
       },
 
       messages: [
         "PictureInPicture:SetupPlayer",
       ],
     },
   };
 }
--- a/toolkit/profile/nsToolkitProfileService.cpp
+++ b/toolkit/profile/nsToolkitProfileService.cpp
@@ -836,18 +836,20 @@ nsToolkitProfileService::SelectStartupPr
   auto allocated = MakeUnique<UniqueFreePtr<char>[]>(argc);
 
   for (int i = 0; i < argc; i++) {
     allocated[i].reset(ToNewCString(aArgv[i]));
     argv[i] = allocated[i].get();
   }
   argv[argc] = nullptr;
 
+  bool wasDefault;
   nsresult rv = SelectStartupProfile(&argc, argv.get(), aIsResetting, aRootDir,
-                                     aLocalDir, aProfile, aDidCreate);
+                                     aLocalDir, aProfile, aDidCreate,
+                                     &wasDefault);
 
   // Since we were called outside of the normal startup path complete any
   // startup tasks.
   if (NS_SUCCEEDED(rv)) {
     CompleteStartup();
   }
 
   return rv;
@@ -869,23 +871,25 @@ nsToolkitProfileService::SelectStartupPr
  * returned in aProfile.
  * aDidCreate will be set to true if a new profile was created.
  * This function should be called once at startup and will fail if called again.
  * aArgv should be an array of aArgc + 1 strings, the last element being null.
  * Both aArgv and aArgc will be mutated.
  */
 nsresult nsToolkitProfileService::SelectStartupProfile(
     int* aArgc, char* aArgv[], bool aIsResetting, nsIFile** aRootDir,
-    nsIFile** aLocalDir, nsIToolkitProfile** aProfile, bool* aDidCreate) {
+    nsIFile** aLocalDir, nsIToolkitProfile** aProfile, bool* aDidCreate,
+    bool* aWasDefaultSelection) {
   if (mStartupProfileSelected) {
     return NS_ERROR_ALREADY_INITIALIZED;
   }
 
   mStartupProfileSelected = true;
   *aDidCreate = false;
+  *aWasDefaultSelection = false;
 
   nsresult rv;
   const char* arg;
 
   // Use the profile specified in the environment variables (generally from an
   // app initiated restart).
   nsCOMPtr<nsIFile> lf = GetFileFromEnv("XRE_PROFILE_PATH");
   if (lf) {
@@ -1087,30 +1091,31 @@ nsresult nsToolkitProfileService::Select
                "Error: argument --profilemanager is invalid when argument "
                "--osint is specified\n");
     return NS_ERROR_FAILURE;
   }
   if (ar == ARG_FOUND) {
     return NS_ERROR_SHOW_PROFILE_MANAGER;
   }
 
-  // We've been told not to use the selected profile automatically.
-  if (!mStartWithLast) {
-    return NS_ERROR_SHOW_PROFILE_MANAGER;
-  }
-
   // If this is a first run then create a new profile.
   if (mIsFirstRun) {
     if (aIsResetting) {
       // We don't want to create a fresh profile when we're attempting a
       // profile reset so just bail out here, the calling code will handle it.
       *aProfile = nullptr;
       return NS_OK;
     }
 
+    // If we're configured to always show the profile manager then don't create
+    // a new profile to use.
+    if (!mStartWithLast) {
+      return NS_ERROR_SHOW_PROFILE_MANAGER;
+    }
+
     if (mUseDedicatedProfile) {
       // This is the first run of a dedicated profile install. We have to decide
       // whether to use the default profile used by non-dedicated-profile
       // installs or to create a new profile.
 
       // Find what would have been the default profile for old installs.
       nsCOMPtr<nsIToolkitProfile> profile = mNormalDefault;
       if (mUseDevEditionProfile) {
@@ -1185,30 +1190,20 @@ nsresult nsToolkitProfileService::Select
   GetDefaultProfile(getter_AddRefs(mCurrent));
 
   // None of the profiles was marked as default (generally only happens if the
   // user modifies profiles.ini manually). Let the user choose.
   if (!mCurrent) {
     return NS_ERROR_SHOW_PROFILE_MANAGER;
   }
 
+  // Let the caller know that the profile was selected by default.
+  *aWasDefaultSelection = true;
   mStartupReason = NS_LITERAL_STRING("default");
 
-  // This code block can be removed before riding the trains to 68.
-  if (mUseDedicatedProfile) {
-    nsCString locked;
-    rv = mInstallData.GetString(mInstallHash.get(), "Locked", locked);
-    if (NS_FAILED(rv) || !locked.EqualsLiteral("1")) {
-      // The profile is unlocked. This can only happen if this profile was the
-      // old default profile and it was chosen as the dedicated default on a
-      // previous run. Check later if this is the default app and if so lock it.
-      mMaybeLockProfile = true;
-    }
-  }
-
   // Use the selected profile.
   mCurrent->GetRootDir(aRootDir);
   mCurrent->GetLocalDir(aLocalDir);
   NS_ADDREF(*aProfile = mCurrent);
 
   return NS_OK;
 }
 
--- a/toolkit/profile/nsToolkitProfileService.h
+++ b/toolkit/profile/nsToolkitProfileService.h
@@ -71,17 +71,18 @@ class nsToolkitProfileFactory final : pu
 
 class nsToolkitProfileService final : public nsIToolkitProfileService {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSITOOLKITPROFILESERVICE
 
   nsresult SelectStartupProfile(int* aArgc, char* aArgv[], bool aIsResetting,
                                 nsIFile** aRootDir, nsIFile** aLocalDir,
-                                nsIToolkitProfile** aProfile, bool* aDidCreate);
+                                nsIToolkitProfile** aProfile, bool* aDidCreate,
+                                bool* aWasDefaultSelection);
   nsresult CreateResetProfile(nsIToolkitProfile** aNewProfile);
   nsresult ApplyResetProfile(nsIToolkitProfile* aOldProfile);
   void CompleteStartup();
 
  private:
   friend class nsToolkitProfile;
   friend class nsToolkitProfileFactory;
   friend nsresult NS_NewToolkitProfileService(nsToolkitProfileService**);
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1978,17 +1978,18 @@ static nsresult LockProfile(nsINativeApp
 // 2) check for -P <name>
 // 3) check for --ProfileManager
 // 4) use the default profile, if there is one
 // 5) if there are *no* profiles, set up profile-migration
 // 6) display the profile-manager UI
 static nsresult SelectProfile(nsToolkitProfileService* aProfileSvc,
                               nsINativeAppSupport* aNative, nsIFile** aRootDir,
                               nsIFile** aLocalDir,
-                              nsIToolkitProfile** aProfile) {
+                              nsIToolkitProfile** aProfile,
+                              bool* aWasDefaultSelection) {
   StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
 
   nsresult rv;
 
   if (EnvHasValue("MOZ_RESET_PROFILE_RESTART")) {
     gDoProfileReset = true;
     gDoMigration = true;
     SaveToEnv("MOZ_RESET_PROFILE_RESTART=");
@@ -2026,17 +2027,17 @@ static nsresult SelectProfile(nsToolkitP
   if (ar == ARG_FOUND) {
     gDoMigration = true;
   }
 
   // Ask the profile manager to select the profile directories to use.
   bool didCreate = false;
   rv = aProfileSvc->SelectStartupProfile(&gArgc, gArgv, gDoProfileReset,
                                          aRootDir, aLocalDir, aProfile,
-                                         &didCreate);
+                                         &didCreate, aWasDefaultSelection);
 
   if (rv == NS_ERROR_SHOW_PROFILE_MANAGER) {
     return ShowProfileManager(aProfileSvc, aNative);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (didCreate) {
@@ -3910,19 +3911,21 @@ int XREMain::XRE_mainStartup(bool* aExit
                "your profile directory.\n");
   }
   if (NS_FAILED(rv)) {
     // We failed to choose or create profile - notify user and quit
     ProfileMissingDialog(mNativeApp);
     return 1;
   }
 
+  bool wasDefaultSelection;
   nsCOMPtr<nsIToolkitProfile> profile;
   rv = SelectProfile(mProfileSvc, mNativeApp, getter_AddRefs(mProfD),
-                     getter_AddRefs(mProfLD), getter_AddRefs(profile));
+                     getter_AddRefs(mProfLD), getter_AddRefs(profile),
+                     &wasDefaultSelection);
   if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
     *aExitFlag = true;
     return 0;
   }
 
   if (NS_FAILED(rv)) {
     // We failed to choose or create profile - notify user and quit
     ProfileMissingDialog(mNativeApp);
@@ -4014,16 +4017,36 @@ int XREMain::XRE_mainStartup(bool* aExit
                  gRestartArgv, mAppData->version);
   if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
     SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
     *aExitFlag = true;
     return 0;
   }
 #endif
 
+  // We now know there is no existing instance using the selected profile. If
+  // the profile wasn't selected by specific command line arguments and the
+  // user has chosen to show the profile manager on startup then do that.
+  if (wasDefaultSelection) {
+    bool useSelectedProfile;
+    rv = mProfileSvc->GetStartWithLastProfile(&useSelectedProfile);
+    NS_ENSURE_SUCCESS(rv, 1);
+
+    if (!useSelectedProfile) {
+      rv = ShowProfileManager(mProfileSvc, mNativeApp);
+      if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
+        *aExitFlag = true;
+        return 0;
+      }
+      if (NS_FAILED(rv)) {
+        return 1;
+      }
+    }
+  }
+
   // We always want to lock the profile even if we're actually going to reset
   // it later.
   rv = LockProfile(mNativeApp, mProfD, mProfLD, profile,
                    getter_AddRefs(mProfileLock));
   if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS || rv == NS_ERROR_ABORT) {
     *aExitFlag = true;
     return 0;
   } else if (NS_FAILED(rv)) {
--- a/tools/tryselect/cli.py
+++ b/tools/tryselect/cli.py
@@ -63,17 +63,17 @@ COMMON_ARGUMENT_GROUPS = {
          {'action': 'store_true',
           'default': False,
           'help': "Use the full set of tasks as input to fzf (instead of "
                   "target tasks).",
           }],
         [['-p', '--parameters'],
          {'default': None,
           'help': "Use the given parameters.yml to generate tasks, "
-                  "defaults to latest parameters.yml from mozilla-central",
+                  "defaults to a default set of parameters",
           }],
     ],
 }
 
 
 class BaseTryParser(ArgumentParser):
     name = 'try'
     common_groups = ['push', 'preset']
--- a/tools/tryselect/tasks.py
+++ b/tools/tryselect/tasks.py
@@ -50,18 +50,16 @@ def invalidate(cache, root):
     tmod = max(os.path.getmtime(os.path.join(tc_dir, p)) for p, _ in FileFinder(tc_dir))
     cmod = os.path.getmtime(cache)
 
     if tmod > cmod:
         os.remove(cache)
 
 
 def generate_tasks(params, full, root):
-    params = params or "project=mozilla-central"
-
     # Try to delete the old taskgraph cache directory.
     old_cache_dir = os.path.join(get_state_dir(), 'cache', 'taskgraph')
     if os.path.isdir(old_cache_dir):
         shutil.rmtree(old_cache_dir)
 
     root_hash = hashlib.sha256(os.path.abspath(root)).hexdigest()
     cache_dir = os.path.join(get_state_dir(), 'cache', root_hash, 'taskgraph')
 
--- a/xpfe/appshell/nsAppShellService.cpp
+++ b/xpfe/appshell/nsAppShellService.cpp
@@ -47,16 +47,17 @@
 
 #include "nsWebBrowser.h"
 
 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
 #  include "EventTracer.h"
 #endif
 
 using namespace mozilla;
+using mozilla::dom::BrowsingContext;
 using mozilla::intl::LocaleService;
 
 // Default URL for the hidden window, can be overridden by a pref on Mac
 #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
 
 class nsIAppShell;
 
 nsAppShellService::nsAppShellService()
@@ -465,23 +466,27 @@ nsAppShellService::CreateWindowlessBrows
     NS_ERROR("Couldn't create instance of stub widget");
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv =
       widget->Create(nullptr, 0, LayoutDeviceIntRect(0, 0, 0, 0), nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // Create a BrowsingContext for our windowless browser.
+  RefPtr<BrowsingContext> browsingContext =
+      BrowsingContext::Create(nullptr, nullptr, EmptyString(),
+                              aIsChrome ? BrowsingContext::Type::Chrome
+                                        : BrowsingContext::Type::Content);
+
   /* Next, we create an instance of nsWebBrowser. Instances of this class have
    * an associated doc shell, which is what we're interested in.
    */
   nsCOMPtr<nsIWebBrowser> browser =
-      nsWebBrowser::Create(stub, widget, OriginAttributes(), nullptr,
-                           aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
-                                     : nsIDocShellTreeItem::typeContentWrapper);
+      nsWebBrowser::Create(stub, widget, OriginAttributes(), browsingContext);
 
   if (NS_WARN_IF(!browser)) {
     NS_ERROR("Couldn't create instance of nsWebBrowser!");
     return NS_ERROR_FAILURE;
   }
 
   // Make sure the container window owns the the nsWebBrowser instance.
   stub->SetBrowser(browser);