commit 346191b515c9a661a28b2bed90a32f22bac56d63
parent 905203a35fbfd65816697064676b37bc80d060fb
Author: Vincent Hilla <vhilla@mozilla.com>
Date: Mon, 29 Dec 2025 08:34:56 +0000
Bug 2002767 - Show initial about:blank as soon as possible after start-up. r=smaug,firefox-desktop-core-reviewers ,Gijs
To improve perceived performance, bug 1336227 showed a blank window early after
start-up. Bug 543435 (sync-about-blank) broke this because the navigation for
the initial about:blank cannot be stopped. win.stop() wouldn't cause a state
stop and to prevent the completing load from breaking other code, we loaded
nothing at all.
This commit introduces a more explicit method to show the initial document.
Differential Revision: https://phabricator.services.mozilla.com/D277151
Diffstat:
3 files changed, 70 insertions(+), 49 deletions(-)
diff --git a/browser/components/BrowserGlue.sys.mjs b/browser/components/BrowserGlue.sys.mjs
@@ -698,6 +698,10 @@ BrowserGlue.prototype = {
docElt.setAttribute("screenX", getValue("screenX"));
docElt.setAttribute("screenY", getValue("screenY"));
+ let appWin = win.docShell.treeOwner
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIAppWindow);
+
// The sizemode="maximized" attribute needs to be set before first paint.
let sizemode = getValue("sizemode");
let width = getValue("width") || 500;
@@ -708,9 +712,6 @@ BrowserGlue.prototype = {
// Set the size to use when the user leaves the maximized mode.
// The persisted size is the outer size, but the height/width
// attributes set the inner size.
- let appWin = win.docShell.treeOwner
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIAppWindow);
height -= appWin.outerToInnerHeightDifferenceInCSSPixels;
width -= appWin.outerToInnerWidthDifferenceInCSSPixels;
docElt.setAttribute("height", height);
@@ -725,8 +726,8 @@ BrowserGlue.prototype = {
// decide to skip some expensive code paths (eg. starting the GPU process).
docElt.setAttribute("windowtype", "navigator:blank");
- // The window becomes visible after OnStopRequest, so make this happen now.
- win.stop();
+ // Show a blank window as soon as possible after start-up
+ appWin.showInitialViewer();
ChromeUtils.addProfilerMarker("earlyBlankFirstPaint", startTime);
win.openTime = ChromeUtils.now();
diff --git a/xpfe/appshell/AppWindow.cpp b/xpfe/appshell/AppWindow.cpp
@@ -1082,31 +1082,6 @@ NS_IMETHODIMP AppWindow::ForceRoundedDimensions() {
return NS_OK;
}
-void AppWindow::OnChromeLoaded() {
- nsresult rv = EnsureContentTreeOwner();
-
- if (NS_SUCCEEDED(rv)) {
- mChromeLoaded = true;
- ApplyChromeFlags();
- SyncAttributesToWidget();
- if (RefPtr ps = GetPresShell()) {
- // Sync window properties now, before showing the window.
- ps->SyncWindowPropertiesIfNeeded();
- }
- if (mWindow) {
- SizeShell();
- if (mShowAfterLoad) {
- SetVisibility(true);
- }
- AddTooltipSupport();
- }
- // At this point the window may have been closed already during Show() or
- // SyncAttributesToWidget(), so AppWindow::Destroy may already have been
- // called. Take care!
- }
- mPersistentAttributesMask += AllPersistentAttributes();
-}
-
bool AppWindow::NeedsTooltipListener() {
nsCOMPtr<dom::Element> docShellElement = GetWindowDOMElement();
if (!docShellElement || docShellElement->IsXULElement()) {
@@ -3035,6 +3010,63 @@ void AppWindow::PersistentAttributesDirty(PersistentAttributes aAttributes,
void AppWindow::FirePersistenceTimer() { SavePersistentAttributes(); }
+void AppWindow::OnChromeLoaded() {
+ MOZ_ASSERT(!mChromeLoaded);
+
+ mChromeLoaded = true;
+ mLockedUntilChromeLoad = false;
+
+#ifdef USE_NATIVE_MENUS
+ ///////////////////////////////
+ // Find the Menubar DOM and Load the menus, hooking them up to the loaded
+ // commands
+ ///////////////////////////////
+ if (!gfxPlatform::IsHeadless()) {
+ if (RefPtr<Document> menubarDoc = mDocShell->GetExtantDocument()) {
+ if (mIsHiddenWindow || !sWaitingForHiddenWindowToLoadNativeMenus) {
+ BeginLoadNativeMenus(menubarDoc, mWindow);
+ } else {
+ sLoadNativeMenusListeners.EmplaceBack(menubarDoc, mWindow);
+ }
+ }
+ }
+#endif // USE_NATIVE_MENUS
+
+ nsresult rv = EnsureContentTreeOwner();
+
+ if (NS_SUCCEEDED(rv)) {
+ ApplyChromeFlags();
+ SyncAttributesToWidget();
+ if (RefPtr ps = GetPresShell()) {
+ // Sync window properties now, before showing the window.
+ ps->SyncWindowPropertiesIfNeeded();
+ }
+ if (mWindow) {
+ SizeShell();
+ if (mShowAfterLoad) {
+ SetVisibility(true);
+ }
+ AddTooltipSupport();
+ }
+ // At this point the window may have been closed already during Show() or
+ // SyncAttributesToWidget(), so AppWindow::Destroy may already have been
+ // called. Take care!
+ }
+ mPersistentAttributesMask += AllPersistentAttributes();
+}
+
+NS_IMETHODIMP
+AppWindow::ShowInitialViewer() {
+ NS_ENSURE_FALSE(mChromeLoaded, NS_ERROR_UNEXPECTED);
+
+ MOZ_ASSERT(mDocShell->GetDocument()->IsUncommittedInitialDocument(),
+ "This method is for showing the initial document, not the result "
+ "of a some navigation");
+
+ OnChromeLoaded();
+ return NS_OK;
+}
+
//----------------------------------------
// nsIWebProgessListener implementation
//----------------------------------------
@@ -3068,25 +3100,6 @@ AppWindow::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
if (eventPWin != rootPWin) return NS_OK;
}
- mChromeLoaded = true;
- mLockedUntilChromeLoad = false;
-
-#ifdef USE_NATIVE_MENUS
- ///////////////////////////////
- // Find the Menubar DOM and Load the menus, hooking them up to the loaded
- // commands
- ///////////////////////////////
- if (!gfxPlatform::IsHeadless()) {
- if (RefPtr<Document> menubarDoc = mDocShell->GetExtantDocument()) {
- if (mIsHiddenWindow || !sWaitingForHiddenWindowToLoadNativeMenus) {
- BeginLoadNativeMenus(menubarDoc, mWindow);
- } else {
- sLoadNativeMenusListeners.EmplaceBack(menubarDoc, mWindow);
- }
- }
- }
-#endif // USE_NATIVE_MENUS
-
OnChromeLoaded();
return NS_OK;
diff --git a/xpfe/appshell/nsIAppWindow.idl b/xpfe/appshell/nsIAppWindow.idl
@@ -151,4 +151,11 @@ interface nsIAppWindow : nsISupports
* Note that tooltips and noautohide popups won't be closed.
*/
void rollupAllPopups();
+
+ /**
+ * Normally, the window is shown when the first navigation completes.
+ * This method does everything that would be done after the first
+ * navigation right now for the initial viewer.
+ */
+ void showInitialViewer();
};