Bug 1822072 - split up tabbrowser's addTab so it's easier to understand, r=dao

Differential Revision: https://phabricator.services.mozilla.com/D170924
This commit is contained in:
Gijs Kruitbosch 2023-03-14 00:29:26 +00:00
parent 402b55c414
commit bbe7f00942

View File

@ -2583,9 +2583,8 @@
* created; this shouldn't normally happen, and an error will be logged
* to the console if it does.
*/
// eslint-disable-next-line complexity
addTab(
aURI,
uriString,
{
allowInheritPrincipal,
allowThirdPartyFixup,
@ -2672,28 +2671,6 @@
(openerBrowser && this.getTabForBrowser(openerBrowser)) ||
(relatedToCurrent && this.selectedTab);
var t = document.createXULElement("tab", { is: "tabbrowser-tab" });
// Tag the tab as being created so extension code can ignore events
// prior to TabOpen.
t.initializingTab = true;
t.openerTab = openerTab;
aURI = aURI || "about:blank";
let aURIObject = null;
try {
aURIObject = Services.io.newURI(aURI);
} catch (ex) {
/* we'll try to fix up this URL later */
}
let lazyBrowserURI;
if (createLazyBrowser && aURI != "about:blank") {
lazyBrowserURI = aURIObject;
aURI = "about:blank";
}
var uriIsAboutBlank = aURI == "about:blank";
// When overflowing, new tabs are scrolled into view smoothly, which
// doesn't go well together with the width transition. So we skip the
// transition in that case.
@ -2703,6 +2680,191 @@
this.tabContainer.getAttribute("overflow") != "true" &&
!gReduceMotion;
let { uri, uriIsAboutBlank, lazyBrowserURI } = this._determineURIToLoad(
uriString,
createLazyBrowser
);
let usingPreloadedContent = false;
let b, t;
try {
t = this._createTab({
uriString,
animate,
userContextId,
openerTab,
createLazyBrowser,
skipAnimation,
pinned,
noInitialLabel,
skipBackgroundNotify,
});
if (!batchInsertingTabs) {
// When we are not restoring a session, we need to know
// insert the tab into the tab container in the correct position
this._insertTabAtIndex(t, {
index,
ownerTab,
openerTab,
pinned,
bulkOrderedOpen,
});
}
({ browser: b, usingPreloadedContent } = this._createBrowserForTab(t, {
uriString,
uri,
preferredRemoteType,
openerBrowser,
uriIsAboutBlank,
referrerInfo,
forceNotRemote,
name,
initialBrowsingContextGroupId,
openWindowInfo,
skipLoad,
}));
if (focusUrlBar) {
b._urlbarFocused = true;
}
// If the caller opts in, create a lazy browser.
if (createLazyBrowser) {
this._createLazyBrowser(t);
if (lazyBrowserURI) {
// Lazy browser must be explicitly registered so tab will appear as
// a switch-to-tab candidate in autocomplete.
this.UrlbarProviderOpenTabs.registerOpenTab(
lazyBrowserURI.spec,
t.userContextId,
PrivateBrowsingUtils.isWindowPrivate(window)
);
b.registeredOpenURI = lazyBrowserURI;
}
SessionStore.setTabState(t, {
entries: [
{
url: lazyBrowserURI ? lazyBrowserURI.spec : "about:blank",
title: lazyTabTitle,
triggeringPrincipal_base64: E10SUtils.serializePrincipal(
triggeringPrincipal
),
},
],
});
} else {
this._insertBrowser(t, true);
// If we were called by frontend and don't have openWindowInfo,
// but we were opened from another browser, set the cross group
// opener ID:
if (openerBrowser && !openWindowInfo) {
b.browsingContext.setCrossGroupOpener(
openerBrowser.browsingContext
);
}
}
} catch (e) {
console.error("Failed to create tab");
console.error(e);
t?.remove();
if (t?.linkedBrowser) {
this._tabFilters.delete(t);
this._tabListeners.delete(t);
this.getPanel(t.linkedBrowser).remove();
}
return null;
}
if (!batchInsertingTabs) {
// Fire a TabOpen event
this._fireTabOpen(t, eventDetail);
this._kickOffBrowserLoad(b, {
uri,
uriString,
usingPreloadedContent,
triggeringPrincipal,
originPrincipal,
originStoragePrincipal,
uriIsAboutBlank,
allowInheritPrincipal,
allowThirdPartyFixup,
fromExternal,
disableTRR,
forceAllowDataURI,
skipLoad,
referrerInfo,
charset,
postData,
csp,
globalHistoryOptions,
triggeringRemoteType,
});
}
// This field is updated regardless if we actually animate
// since it's important that we keep this count correct in all cases.
this.tabAnimationsInProgress++;
if (animate) {
requestAnimationFrame(function() {
// kick the animation off
t.setAttribute("fadein", "true");
});
}
// Additionally send pinned tab events
if (pinned) {
this._notifyPinnedStatus(t);
}
gSharedTabWarning.tabAdded(t);
if (!inBackground) {
this.selectedTab = t;
}
return t;
},
_determineURIToLoad(uriString, createLazyBrowser) {
uriString = uriString || "about:blank";
let aURIObject = null;
try {
aURIObject = Services.io.newURI(uriString);
} catch (ex) {
/* we'll try to fix up this URL later */
}
let lazyBrowserURI;
if (createLazyBrowser && uriString != "about:blank") {
lazyBrowserURI = aURIObject;
uriString = "about:blank";
}
let uriIsAboutBlank = uriString == "about:blank";
return { uri: aURIObject, uriIsAboutBlank, lazyBrowserURI };
},
_createTab({
uriString,
userContextId,
openerTab,
createLazyBrowser,
skipAnimation,
pinned,
noInitialLabel,
skipBackgroundNotify,
animate,
}) {
var t = document.createXULElement("tab", { is: "tabbrowser-tab" });
// Tag the tab as being created so extension code can ignore events
// prior to TabOpen.
t.initializingTab = true;
t.openerTab = openerTab;
// Related tab inherits current tab's user context unless a different
// usercontextid is specified
if (userContextId == null && openerTab) {
@ -2710,11 +2872,11 @@
}
if (!noInitialLabel) {
if (isBlankPageURL(aURI)) {
if (isBlankPageURL(uriString)) {
t.setAttribute("label", this.tabContainer.emptyTabTitle);
} else {
// Set URL as label so that the tab isn't empty initially.
this.setInitialTabTitle(t, aURI, {
this.setInitialTabTitle(t, uriString, {
beforeTabOpen: true,
isURL: true,
});
@ -2755,246 +2917,196 @@
UserInteraction.update("browser.tabs.opening", "animated", window);
}
let usingPreloadedContent = false;
let b;
return t;
},
try {
if (!batchInsertingTabs) {
// When we are not restoring a session, we need to know
// insert the tab into the tab container in the correct position
this._insertTabAtIndex(t, {
index,
ownerTab,
openerTab,
pinned,
bulkOrderedOpen,
});
}
_createBrowserForTab(
tab,
{
uriString,
uri,
name,
preferredRemoteType,
openerBrowser,
uriIsAboutBlank,
referrerInfo,
forceNotRemote,
initialBrowsingContextGroupId,
openWindowInfo,
skipLoad,
}
) {
// If we don't have a preferred remote type, and we have a remote
// opener, use the opener's remote type.
if (!preferredRemoteType && openerBrowser) {
preferredRemoteType = openerBrowser.remoteType;
}
// If we don't have a preferred remote type, and we have a remote
// opener, use the opener's remote type.
if (!preferredRemoteType && openerBrowser) {
preferredRemoteType = openerBrowser.remoteType;
}
let { userContextId } = tab;
var oa = E10SUtils.predictOriginAttributes({ window, userContextId });
var oa = E10SUtils.predictOriginAttributes({ window, userContextId });
// If URI is about:blank and we don't have a preferred remote type,
// then we need to use the referrer, if we have one, to get the
// correct remote type for the new tab.
if (
uriIsAboutBlank &&
!preferredRemoteType &&
referrerInfo &&
referrerInfo.originalReferrer
) {
preferredRemoteType = E10SUtils.getRemoteTypeForURI(
referrerInfo.originalReferrer.spec,
// If URI is about:blank and we don't have a preferred remote type,
// then we need to use the referrer, if we have one, to get the
// correct remote type for the new tab.
if (
uriIsAboutBlank &&
!preferredRemoteType &&
referrerInfo &&
referrerInfo.originalReferrer
) {
preferredRemoteType = E10SUtils.getRemoteTypeForURI(
referrerInfo.originalReferrer.spec,
gMultiProcessBrowser,
gFissionBrowser,
E10SUtils.DEFAULT_REMOTE_TYPE,
null,
oa
);
}
let remoteType = forceNotRemote
? E10SUtils.NOT_REMOTE
: E10SUtils.getRemoteTypeForURI(
uriString,
gMultiProcessBrowser,
gFissionBrowser,
E10SUtils.DEFAULT_REMOTE_TYPE,
preferredRemoteType,
null,
oa
);
let b,
usingPreloadedContent = false;
// If we open a new tab with the newtab URL in the default
// userContext, check if there is a preloaded browser ready.
if (uriString == BROWSER_NEW_TAB_URL && !userContextId) {
b = NewTabPagePreloading.getPreloadedBrowser(window);
if (b) {
usingPreloadedContent = true;
}
}
let remoteType = forceNotRemote
? E10SUtils.NOT_REMOTE
: E10SUtils.getRemoteTypeForURI(
aURI,
gMultiProcessBrowser,
gFissionBrowser,
preferredRemoteType,
null,
oa
);
// If we open a new tab with the newtab URL in the default
// userContext, check if there is a preloaded browser ready.
if (aURI == BROWSER_NEW_TAB_URL && !userContextId) {
b = NewTabPagePreloading.getPreloadedBrowser(window);
if (b) {
usingPreloadedContent = true;
}
}
if (!b) {
// No preloaded browser found, create one.
b = this.createBrowser({
remoteType,
uriIsAboutBlank,
userContextId,
initialBrowsingContextGroupId,
openWindowInfo,
name,
skipLoad,
});
}
t.linkedBrowser = b;
if (focusUrlBar) {
b._urlbarFocused = true;
}
this._tabForBrowser.set(b, t);
t.permanentKey = b.permanentKey;
t._browserParams = {
uriIsAboutBlank,
if (!b) {
// No preloaded browser found, create one.
b = this.createBrowser({
remoteType,
usingPreloadedContent,
};
// If the caller opts in, create a lazy browser.
if (createLazyBrowser) {
this._createLazyBrowser(t);
if (lazyBrowserURI) {
// Lazy browser must be explicitly registered so tab will appear as
// a switch-to-tab candidate in autocomplete.
this.UrlbarProviderOpenTabs.registerOpenTab(
lazyBrowserURI.spec,
userContextId || 0,
PrivateBrowsingUtils.isWindowPrivate(window)
);
b.registeredOpenURI = lazyBrowserURI;
}
SessionStore.setTabState(t, {
entries: [
{
url: lazyBrowserURI ? lazyBrowserURI.spec : "about:blank",
title: lazyTabTitle,
triggeringPrincipal_base64: E10SUtils.serializePrincipal(
triggeringPrincipal
),
},
],
});
} else {
this._insertBrowser(t, true);
// If we were called by frontend and don't have openWindowInfo,
// but we were opened from another browser, set the cross group
// opener ID:
if (openerBrowser && !openWindowInfo) {
b.browsingContext.setCrossGroupOpener(
openerBrowser.browsingContext
);
}
}
} catch (e) {
console.error("Failed to create tab");
console.error(e);
t.remove();
if (t.linkedBrowser) {
this._tabFilters.delete(t);
this._tabListeners.delete(t);
this.getPanel(t.linkedBrowser).remove();
}
return null;
}
// Hack to ensure that the about:newtab, and about:welcome favicon is loaded
// instantaneously, to avoid flickering and improve perceived performance.
this.setDefaultIcon(t, aURIObject);
if (!batchInsertingTabs) {
// Fire a TabOpen event
this._fireTabOpen(t, eventDetail);
if (
!usingPreloadedContent &&
originPrincipal &&
originStoragePrincipal &&
aURI
) {
let { URI_INHERITS_SECURITY_CONTEXT } = Ci.nsIProtocolHandler;
// Unless we know for sure we're not inheriting principals,
// force the about:blank viewer to have the right principal:
if (
!aURIObject ||
doGetProtocolFlags(aURIObject) & URI_INHERITS_SECURITY_CONTEXT
) {
b.createAboutBlankContentViewer(
originPrincipal,
originStoragePrincipal
);
}
}
// If we didn't swap docShells with a preloaded browser
// then let's just continue loading the page normally.
if (
!usingPreloadedContent &&
(!uriIsAboutBlank || !allowInheritPrincipal) &&
!skipLoad
) {
// pretend the user typed this so it'll be available till
// the document successfully loads
if (aURI && !gInitialPages.includes(aURI)) {
b.userTypedValue = aURI;
}
let flags = LOAD_FLAGS_NONE;
if (allowThirdPartyFixup) {
flags |=
LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
}
if (fromExternal) {
flags |= LOAD_FLAGS_FROM_EXTERNAL;
} else if (!triggeringPrincipal.isSystemPrincipal) {
// XXX this code must be reviewed and changed when bug 1616353
// lands.
flags |= LOAD_FLAGS_FIRST_LOAD;
}
if (!allowInheritPrincipal) {
flags |= LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
}
if (disableTRR) {
flags |= LOAD_FLAGS_DISABLE_TRR;
}
if (forceAllowDataURI) {
flags |= LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
}
try {
b.fixupAndLoadURIString(aURI, {
flags,
triggeringPrincipal,
referrerInfo,
charset,
postData,
csp,
globalHistoryOptions,
triggeringRemoteType,
});
} catch (ex) {
console.error(ex);
}
}
}
// This field is updated regardless if we actually animate
// since it's important that we keep this count correct in all cases.
this.tabAnimationsInProgress++;
if (animate) {
requestAnimationFrame(function() {
// kick the animation off
t.setAttribute("fadein", "true");
uriIsAboutBlank,
userContextId,
initialBrowsingContextGroupId,
openWindowInfo,
name,
skipLoad,
});
}
// Additionally send pinned tab events
if (pinned) {
this._notifyPinnedStatus(t);
tab.linkedBrowser = b;
this._tabForBrowser.set(b, tab);
tab.permanentKey = b.permanentKey;
tab._browserParams = {
uriIsAboutBlank,
remoteType,
usingPreloadedContent,
};
// Hack to ensure that the about:newtab, and about:welcome favicon is loaded
// instantaneously, to avoid flickering and improve perceived performance.
this.setDefaultIcon(tab, uri);
return { browser: b, usingPreloadedContent };
},
_kickOffBrowserLoad(
browser,
{
uri,
uriString,
usingPreloadedContent,
triggeringPrincipal,
originPrincipal,
originStoragePrincipal,
uriIsAboutBlank,
allowInheritPrincipal,
allowThirdPartyFixup,
fromExternal,
disableTRR,
forceAllowDataURI,
skipLoad,
referrerInfo,
charset,
postData,
csp,
globalHistoryOptions,
triggeringRemoteType,
}
) {
if (
!usingPreloadedContent &&
originPrincipal &&
originStoragePrincipal &&
uriString
) {
let { URI_INHERITS_SECURITY_CONTEXT } = Ci.nsIProtocolHandler;
// Unless we know for sure we're not inheriting principals,
// force the about:blank viewer to have the right principal:
if (!uri || doGetProtocolFlags(uri) & URI_INHERITS_SECURITY_CONTEXT) {
browser.createAboutBlankContentViewer(
originPrincipal,
originStoragePrincipal
);
}
}
gSharedTabWarning.tabAdded(t);
// If we didn't swap docShells with a preloaded browser
// then let's just continue loading the page normally.
if (
!usingPreloadedContent &&
(!uriIsAboutBlank || !allowInheritPrincipal) &&
!skipLoad
) {
// pretend the user typed this so it'll be available till
// the document successfully loads
if (uriString && !gInitialPages.includes(uriString)) {
browser.userTypedValue = uriString;
}
if (!inBackground) {
this.selectedTab = t;
let flags = LOAD_FLAGS_NONE;
if (allowThirdPartyFixup) {
flags |=
LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
}
if (fromExternal) {
flags |= LOAD_FLAGS_FROM_EXTERNAL;
} else if (!triggeringPrincipal.isSystemPrincipal) {
// XXX this code must be reviewed and changed when bug 1616353
// lands.
flags |= LOAD_FLAGS_FIRST_LOAD;
}
if (!allowInheritPrincipal) {
flags |= LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
}
if (disableTRR) {
flags |= LOAD_FLAGS_DISABLE_TRR;
}
if (forceAllowDataURI) {
flags |= LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
}
try {
browser.fixupAndLoadURIString(uriString, {
flags,
triggeringPrincipal,
referrerInfo,
charset,
postData,
csp,
globalHistoryOptions,
triggeringRemoteType,
});
} catch (ex) {
console.error(ex);
}
}
return t;
},
addMultipleTabs(restoreTabsLazily, selectTab, aPropertiesTabs) {