Bug 1442694 - Preopen pinned tabs before session restore r=Gijs

When we open firefox with pinned tabs, we first paint a window with
one tab open, and then that tab gets displaced after the pinned tabs
come in. This aims to ensure that our first paint contains the
pinned tab, so that we don't have tabs moving around after first
paint.

MozReview-Commit-ID: GC1y6NlgLTd

Differential Revision: https://phabricator.services.mozilla.com/D18742

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Doug Thayer 2019-02-25 19:19:07 +00:00
Родитель 0e903787da
Коммит 978e0344ff
5 изменённых файлов: 109 добавлений и 22 удалений

Просмотреть файл

@ -22,6 +22,11 @@
display: none;
}
.tab-icon-pending[preopened],
.tab-icon-image[preopened] {
visibility: hidden;
}
.tab-sharing-icon-overlay[sharing]:not([selected]),
.tab-icon-overlay[soundplaying][pinned],
.tab-icon-overlay[muted][pinned],

Просмотреть файл

@ -32,6 +32,7 @@ window._gBrowser = {
window.addEventListener("occlusionstatechange", this);
this._setupInitialBrowserAndTab();
this._preopenPinnedTabs();
if (Services.prefs.getBoolPref("browser.display.use_system_colors")) {
this.tabpanels.style.backgroundColor = "-moz-default-background-color";
@ -383,6 +384,29 @@ window._gBrowser = {
browser.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
},
_preopenPinnedTabs() {
let numPinnedTabs = 0;
let windows = browserWindows();
windows.getNext();
let isOnlyWindow = !windows.hasMoreElements();
if (isOnlyWindow) {
numPinnedTabs = Services.prefs.getIntPref("browser.tabs.firstWindowRestore.numPinnedTabs", 0);
}
for (let i = 0; i < numPinnedTabs; i++) {
let tab = this.addTrustedTab("about:blank", {
skipAnimation: true,
noInitialLabel: true,
skipBackgroundNotify: true,
createLazyBrowser: true,
pinned: true,
isForFirstWindowRestore: true,
});
tab.setAttribute("preopened", "true");
}
},
/**
* BEGIN FORWARDED BROWSER PROPERTIES. IF YOU ADD A PROPERTY TO THE BROWSER ELEMENT
* MAKE SURE TO ADD IT HERE AS WELL.
@ -593,14 +617,32 @@ window._gBrowser = {
this.tabContainer._updateCloseButtons();
},
_notifyPinnedStatus(aTab) {
_sendPinnedTabContentMessage(aTab) {
this.getBrowserForTab(aTab).messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: aTab.pinned });
},
_notifyPinnedStatus(aTab, aDeferContentMessage = false) {
if (!aDeferContentMessage) {
this._sendPinnedTabContentMessage(aTab);
}
let event = document.createEvent("Events");
event.initEvent(aTab.pinned ? "TabPinned" : "TabUnpinned", true, false);
aTab.dispatchEvent(event);
},
_maybeUpdateNumPinnedTabsPref() {
if (BrowserWindowTracker.getTopWindow() == window) {
Services.prefs.setIntPref("browser.tabs.firstWindowRestore.numPinnedTabs",
this._numPinnedTabs);
}
},
activatePreopenedPinnedTab(aTab) {
this._insertBrowser(aTab);
this._sendPinnedTabContentMessage(aTab);
},
pinTab(aTab) {
if (aTab.pinned)
return;
@ -612,6 +654,7 @@ window._gBrowser = {
aTab.setAttribute("pinned", "true");
this._updateTabBarForPinnedTabs();
this._notifyPinnedStatus(aTab);
this._maybeUpdateNumPinnedTabsPref();
},
unpinTab(aTab) {
@ -623,6 +666,7 @@ window._gBrowser = {
aTab.style.marginInlineStart = "";
this._updateTabBarForPinnedTabs();
this._notifyPinnedStatus(aTab);
this._maybeUpdateNumPinnedTabsPref();
},
previewTab(aTab, aCallback) {
@ -2296,6 +2340,7 @@ window._gBrowser = {
forceNotRemote,
fromExternal,
index,
isForFirstWindowRestore,
lazyTabTitle,
name,
nextTabParentId,
@ -2479,6 +2524,9 @@ window._gBrowser = {
if (pinned) {
this._updateTabBarForPinnedTabs();
if (!isForFirstWindowRestore) {
this._maybeUpdateNumPinnedTabsPref();
}
}
this.tabContainer._setPositionalAttributes();
@ -2558,13 +2606,15 @@ window._gBrowser = {
userContextId);
b.registeredOpenURI = lazyBrowserURI;
}
SessionStore.setTabState(t, {
entries: [{
url: lazyBrowserURI ? lazyBrowserURI.spec : "about:blank",
title: lazyTabTitle,
triggeringPrincipal_base64: E10SUtils.serializePrincipal(triggeringPrincipal),
}],
});
if (!isForFirstWindowRestore) {
SessionStore.setTabState(t, {
entries: [{
url: lazyBrowserURI ? lazyBrowserURI.spec : "about:blank",
title: lazyTabTitle,
triggeringPrincipal_base64: E10SUtils.serializePrincipal(triggeringPrincipal),
}],
});
}
} else {
this._insertBrowser(t, true);
}
@ -2602,7 +2652,9 @@ window._gBrowser = {
// If we didn't swap docShells with a preloaded browser
// then let's just continue loading the page normally.
if (!usingPreloadedContent && (!uriIsAboutBlank || !allowInheritPrincipal)) {
if (!usingPreloadedContent &&
!createLazyBrowser &&
(!uriIsAboutBlank || !allowInheritPrincipal)) {
// pretend the user typed this so it'll be available till
// the document successfully loads
if (aURI && !gInitialPages.includes(aURI)) {
@ -2655,7 +2707,7 @@ window._gBrowser = {
// Additionally send pinned tab events
if (pinned) {
this._notifyPinnedStatus(t);
this._notifyPinnedStatus(t, isForFirstWindowRestore);
}
return t;
@ -3153,8 +3205,10 @@ window._gBrowser = {
this.tabs[i]._tPos = i;
if (!this._windowIsClosing) {
if (wasPinned)
if (wasPinned) {
this.tabContainer._positionPinnedTabs();
this._maybeUpdateNumPinnedTabsPref();
}
// update tab close buttons state
this.tabContainer._updateCloseButtons();
@ -3839,7 +3893,6 @@ window._gBrowser = {
skipAnimation: true,
index: aIndex,
createLazyBrowser,
allowInheritPrincipal: createLazyBrowser,
};
let numPinned = this._numPinnedTabs;
@ -5016,6 +5069,7 @@ class TabProgressListener {
this.mTab.removeAttribute("crashed");
}
this.mTab.removeAttribute("preopened");
if (this._shouldShowProgress(aRequest)) {
if (!(aStateFlags & Ci.nsIWebProgressListener.STATE_RESTORING) &&
aWebProgress && aWebProgress.isTopLevel) {

Просмотреть файл

@ -1937,10 +1937,10 @@
anonid="tab-throbber"
class="tab-throbber"
layer="true"/>
<xul:hbox xbl:inherits="fadein,pinned,busy,progress,selected=visuallyselected,pendingicon"
<xul:hbox xbl:inherits="fadein,pinned,busy,progress,selected=visuallyselected,pendingicon,preopened"
anonid="tab-icon-pending"
class="tab-icon-pending"/>
<xul:image xbl:inherits="src=image,triggeringprincipal=iconloadingprincipal,requestcontextid,fadein,pinned,selected=visuallyselected,busy,crashed,sharing"
<xul:image xbl:inherits="src=image,triggeringprincipal=iconloadingprincipal,requestcontextid,fadein,pinned,selected=visuallyselected,busy,crashed,sharing,preopened"
anonid="tab-icon-image"
class="tab-icon-image"
validate="never"

Просмотреть файл

@ -731,6 +731,7 @@ var SessionStoreInternal = {
this._prefBranch.addObserver("sessionstore.max_windows_undo", this, true);
this._restore_on_demand = this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
this._restore_pinned_tabs_on_demand = this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand");
this._prefBranch.addObserver("sessionstore.restore_on_demand", this, true);
gResistFingerprintingEnabled = Services.prefs.getBoolPref("privacy.resistFingerprinting");
@ -3203,6 +3204,7 @@ var SessionStoreInternal = {
if (!uriObj || (uriObj && !window.gBrowser.isLocalAboutURI(uriObj))) {
tab.setAttribute("busy", "true");
}
tab.removeAttribute("preopened");
// Hack to ensure that the about:home, about:newtab, and about:welcome
// favicon is loaded instantaneously, to avoid flickering and improve
@ -3650,7 +3652,7 @@ var SessionStoreInternal = {
// We need to keep track of the initially open tabs so that they
// can be moved to the end of the restored tabs.
let initialTabs;
let initialTabs = [];
if (!overwriteTabs && firstWindow) {
initialTabs = Array.slice(tabbrowser.tabs);
}
@ -3658,8 +3660,11 @@ var SessionStoreInternal = {
// Get rid of tabs that aren't needed anymore.
if (overwriteTabs) {
for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) {
if (!tabbrowser.tabs[i].selected) {
if (!tabbrowser.tabs[i].selected &&
!tabbrowser.tabs[i].hasAttribute("preopened")) {
tabbrowser.removeTab(tabbrowser.tabs[i]);
} else if (tabbrowser.tabs[i].hasAttribute("preopened")) {
initialTabs.push(tabbrowser.tabs[i]);
}
}
}
@ -3678,13 +3683,24 @@ var SessionStoreInternal = {
if (select &&
tabbrowser.selectedTab.userContextId == userContextId) {
tab = tabbrowser.selectedTab;
if (!tabData.pinned) {
if (tab.pinned && !tabData.pinned) {
tabbrowser.unpinTab(tab);
} else if (!tab.pinned && tabData.pinned) {
tabbrowser.removeTab(tabbrowser.tabs[t]);
tabbrowser.pinTab(tab);
tabbrowser.moveTabTo(tab, t);
}
tabbrowser.moveTabToEnd();
if (aWindow.gMultiProcessBrowser && !tab.linkedBrowser.isRemoteBrowser) {
tabbrowser.updateBrowserRemoteness(tab.linkedBrowser, true);
}
} else if (tabData.pinned &&
tabbrowser.tabs[t] &&
tabbrowser.tabs[t].pinned &&
!tabbrowser.tabs[t].linkedPanel) {
tab = tabbrowser.tabs[t];
tabbrowser.activatePreopenedPinnedTab(tab);
}
// Add a new tab if needed.
@ -3733,11 +3749,14 @@ var SessionStoreInternal = {
}
// Move the originally open tabs to the end.
if (initialTabs) {
let endPosition = tabbrowser.tabs.length - 1;
for (let i = 0; i < initialTabs.length; i++) {
tabbrowser.unpinTab(initialTabs[i]);
tabbrowser.moveTabTo(initialTabs[i], endPosition);
let endPosition = tabbrowser.tabs.length - 1;
for (let tab of initialTabs) {
if (tab.hasAttribute("preopened") &&
!tab.linkedPanel) {
tabbrowser.removeTab(tab);
} else if (!tab.hasAttribute("preopened")) {
tabbrowser.unpinTab(tab);
tabbrowser.moveTabTo(tab, endPosition);
}
}
@ -3998,6 +4017,9 @@ var SessionStoreInternal = {
for (let t = 0; t < aTabs.length; t++) {
if (t != selectedIndex) {
this.restoreTab(aTabs[t], aTabData[t]);
if (this._restore_pinned_tabs_on_demand) {
aTabs[t].removeAttribute("preopened");
}
}
}
},

Просмотреть файл

@ -96,6 +96,11 @@ function _untrackWindowOrder(window) {
_trackedWindows.splice(idx, 1);
}
function _trackPinnedTabs(window) {
Services.prefs.setIntPref("browser.tabs.firstWindowRestore.numPinnedTabs",
window.gBrowser._numPinnedTabs);
}
// Methods that impact a window. Put into single object for organization.
var WindowHelper = {
addWindow(window) {
@ -138,6 +143,7 @@ var WindowHelper = {
_untrackWindowOrder(window);
_trackWindowOrder(window);
_trackPinnedTabs(window);
_updateCurrentContentOuterWindowID(window.gBrowser.selectedBrowser);
},