commit 15dba1db03c812191a3fcd04d0542e12b3c3b85f
parent 4552a2f867a8074cfdd2c69fdde2aab0e33f129a
Author: Cristina Horotan <chorotan@mozilla.com>
Date: Fri, 21 Nov 2025 12:55:44 +0200
Revert "Bug 1948948 - Removed browser.tabs.documentchannel.parent-controlled. r=farre,tabbrowser-reviewers,sthompson" for causing build bustages on CanonicalBrowsingContext.cpp
This reverts commit 66d18cee690a1df212878254c24f1730fee6af63.
Diffstat:
7 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
@@ -8718,15 +8718,16 @@
// before the location changed.
this.mBrowser.userTypedValue = null;
- // When SHIP is enabled and a load gets cancelled due to another one
+ // When browser.tabs.documentchannel.parent-controlled pref and SHIP
+ // are enabled and a load gets cancelled due to another one
// starting, the error is NS_BINDING_CANCELLED_OLD_LOAD.
// When these prefs are not enabled, the error is different and
// that's why we still want to look at the isNavigating flag.
// We could add a workaround and make sure that in the alternative
// codepaths we would also omit the same error, but considering
// how we will be enabling fission by default soon, we can keep
- // using isNavigating for now, and remove it when SHIP is enabled
- // by default.
+ // using isNavigating for now, and remove it when the
+ // parent-controlled pref and SHIP are enabled by default.
// Bug 1725716 has been filed to consider removing isNavigating
// field alltogether.
let isNavigating = this.mBrowser.isNavigating;
diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp
@@ -2182,6 +2182,10 @@ nsresult BrowsingContext::LoadURI(nsDocShellLoadState* aLoadState,
wgc->SendLoadURI(this, mozilla::WrapNotNull(aLoadState), aSetNavigating);
}
} else if (XRE_IsParentProcess()) {
+ if (Canonical()->LoadInParent(aLoadState, aSetNavigating)) {
+ return NS_OK;
+ }
+
if (ContentParent* cp = Canonical()->GetContentParent()) {
// Attempt to initiate this load immediately in the parent, if it succeeds
// it'll return a unique identifier so that we can find it later.
diff --git a/docshell/base/CanonicalBrowsingContext.cpp b/docshell/base/CanonicalBrowsingContext.cpp
@@ -2713,13 +2713,42 @@ bool CanonicalBrowsingContext::SupportsLoadingInParent(
return true;
}
+bool CanonicalBrowsingContext::LoadInParent(nsDocShellLoadState* aLoadState,
+ bool aSetNavigating) {
+ // We currently only support starting loads directly from the
+ // CanonicalBrowsingContext for top-level BCs.
+ // We currently only support starting loads directly from the
+ // CanonicalBrowsingContext for top-level BCs.
+ if (!IsTopContent() || !GetContentParent() ||
+ !StaticPrefs::browser_tabs_documentchannel_parent_controlled()) {
+ return false;
+ }
+
+ uint64_t outerWindowId = 0;
+ if (!SupportsLoadingInParent(aLoadState, &outerWindowId)) {
+ return false;
+ }
+
+ MOZ_ASSERT(!aLoadState->URI()->SchemeIs("javascript"));
+
+ MOZ_ALWAYS_SUCCEEDS(
+ SetParentInitiatedNavigationEpoch(++gParentInitiatedNavigationEpoch));
+ // Note: If successful, this will recurse into StartDocumentLoad and
+ // set mCurrentLoad to the DocumentLoadListener instance created.
+ // Ideally in the future we will only start loads from here, and we can
+ // just set this directly instead.
+ return net::DocumentLoadListener::LoadInParent(this, aLoadState,
+ aSetNavigating);
+}
+
bool CanonicalBrowsingContext::AttemptSpeculativeLoadInParent(
nsDocShellLoadState* aLoadState) {
// We currently only support starting loads directly from the
// CanonicalBrowsingContext for top-level BCs.
// We currently only support starting loads directly from the
// CanonicalBrowsingContext for top-level BCs.
- if (!IsTopContent() || !GetContentParent()) {
+ if (!IsTopContent() || !GetContentParent() ||
+ (StaticPrefs::browser_tabs_documentchannel_parent_controlled())) {
return false;
}
@@ -2736,6 +2765,18 @@ bool CanonicalBrowsingContext::AttemptSpeculativeLoadInParent(
bool CanonicalBrowsingContext::StartDocumentLoad(
net::DocumentLoadListener* aLoad) {
+ // If we're controlling loads from the parent, then starting a new load means
+ // that we need to cancel any existing ones.
+ if (StaticPrefs::browser_tabs_documentchannel_parent_controlled() &&
+ mCurrentLoad) {
+ // Make sure we are not loading a javascript URI.
+ MOZ_ASSERT(!aLoad->IsLoadingJSURI());
+
+ // If we want to do a download, don't cancel the current navigation.
+ if (!aLoad->IsDownload()) {
+ mCurrentLoad->Cancel(NS_BINDING_CANCELLED_OLD_LOAD, ""_ns);
+ }
+ }
mCurrentLoad = aLoad;
if (NS_FAILED(SetCurrentLoadIdentifier(Some(aLoad->GetLoadIdentifier())))) {
diff --git a/docshell/base/CanonicalBrowsingContext.h b/docshell/base/CanonicalBrowsingContext.h
@@ -286,6 +286,12 @@ class CanonicalBrowsingContext final : public BrowsingContext {
bool HasCreatedMediaController() const;
// Attempts to start loading the given load state in this BrowsingContext,
+ // without requiring any communication from a docshell. This will handle
+ // computing the right process to load in, and organising handoff to
+ // the right docshell when we get a response.
+ bool LoadInParent(nsDocShellLoadState* aLoadState, bool aSetNavigating);
+
+ // Attempts to start loading the given load state in this BrowsingContext,
// in parallel with a DocumentChannelChild being created in the docshell.
// Requires the DocumentChannel to connect with this load for it to
// complete successfully.
diff --git a/docshell/test/browser/browser_backforward_userinteraction_systemprincipal.js b/docshell/test/browser/browser_backforward_userinteraction_systemprincipal.js
@@ -10,7 +10,18 @@ const TEST_PAGE =
) + "dummy_page.html";
async function runTest(privilegedLoad) {
- for (let requireUserInteraction of [true, false]) {
+ let prefVals;
+ // Test with both pref on and off, unless parent-controlled pref is enabled.
+ // This distinction can be removed once SHIP is enabled by default.
+ if (
+ Services.prefs.getBoolPref("browser.tabs.documentchannel.parent-controlled")
+ ) {
+ prefVals = [false];
+ } else {
+ prefVals = [true, false];
+ }
+
+ for (let requireUserInteraction of prefVals) {
Services.prefs.setBoolPref(
"browser.navigation.requireUserInteraction",
requireUserInteraction
diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
@@ -1952,6 +1952,13 @@
value: 2
mirror: always
+# If set, use DocumentChannel to directly initiate loads entirely
+# from parent-process BrowsingContexts
+- name: browser.tabs.documentchannel.parent-controlled
+ type: bool
+ value: false
+ mirror: always
+
# If set, middle clicking on a link opens the link in a new tab.
- name: browser.tabs.opentabfor.middleclick
type: bool
diff --git a/xpcom/base/ErrorList.py b/xpcom/base/ErrorList.py
@@ -963,7 +963,8 @@ with modules["URILOADER"]:
# doesn't need to be reparsed from the original source.
errors["NS_ERROR_PARSED_DATA_CACHED"] = FAILURE(33)
- # When SHIP is enabled and a load gets cancelled due to another one
+ # When browser.tabs.documentchannel.parent-controlled pref and SHIP
+ # are enabled and a load gets cancelled due to another one
# starting, the error is NS_BINDING_CANCELLED_OLD_LOAD.
errors["NS_BINDING_CANCELLED_OLD_LOAD"] = FAILURE(39)