1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 * This module is in charge of preloading 'new tab' pages for use when
7 * the user opens a new tab.
10 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
14 ChromeUtils.defineESModuleGetters(lazy, {
15 AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs",
16 BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
17 E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
18 PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
21 export let NewTabPagePreloading = {
22 // Maximum number of instances of a given page we'll preload at any time.
23 // Because we preload about:newtab for normal windows, and about:privatebrowsing
24 // for private ones, we could have 3 of each.
27 // How many preloaded tabs we have, across all windows, for the private and non-private
38 !lazy.AboutNewTab.newTabURLOverridden
43 * Create a browser in the right process type.
53 let oa = lazy.E10SUtils.predictOriginAttributes({ window: win });
55 let remoteType = lazy.E10SUtils.getRemoteTypeForURI(
59 lazy.E10SUtils.DEFAULT_REMOTE_TYPE,
63 let browser = gBrowser.createBrowser({
64 isPreloadBrowser: true,
67 gBrowser.preloadedBrowser = browser;
69 let panel = gBrowser.getPanel(browser);
70 gBrowser.tabpanels.appendChild(panel);
76 * Move the contents of a preload browser across to a different window.
78 _adoptBrowserFromOtherWindow(window) {
79 let winPrivate = lazy.PrivateBrowsingUtils.isWindowPrivate(window);
80 // Grab the least-recently-focused window with a preloaded browser:
81 let oldWin = lazy.BrowserWindowTracker.orderedWindows
84 winPrivate == lazy.PrivateBrowsingUtils.isWindowPrivate(w) &&
86 w.gBrowser.preloadedBrowser
93 // Don't call getPreloadedBrowser because it'll consume the browser:
94 let oldBrowser = oldWin.gBrowser.preloadedBrowser;
95 oldWin.gBrowser.preloadedBrowser = null;
97 let newBrowser = this._createBrowser(window);
99 oldBrowser.swapBrowsers(newBrowser);
101 newBrowser.permanentKey = oldBrowser.permanentKey;
103 oldWin.gBrowser.getPanel(oldBrowser).remove();
107 maybeCreatePreloadedBrowser(window) {
108 // If we're not enabled, have already got one, are in a popup window, or the
109 // window is minimized / occluded, don't bother creating a preload browser -
113 window.gBrowser.preloadedBrowser ||
114 !window.toolbar.visible ||
115 window.document.hidden
120 // Don't bother creating a preload browser if we're not in the top set of windows:
121 let windowPrivate = lazy.PrivateBrowsingUtils.isWindowPrivate(window);
122 let countKey = windowPrivate ? "private" : "normal";
123 let topWindows = lazy.BrowserWindowTracker.orderedWindows.filter(
124 w => lazy.PrivateBrowsingUtils.isWindowPrivate(w) == windowPrivate
126 if (topWindows.indexOf(window) >= this.MAX_COUNT) {
130 // If we're in the top set of windows, and we already have enough preloaded
131 // tabs, don't create yet another one, just steal an existing one:
132 if (this.browserCounts[countKey] >= this.MAX_COUNT) {
133 let browser = this._adoptBrowserFromOtherWindow(window);
134 // We can potentially get null here if we couldn't actually find another
135 // browser to adopt from. This can be the case when there's a mix of
136 // private and non-private windows, for instance.
142 let browser = this._createBrowser(window);
143 browser.loadURI(Services.io.newURI(window.BROWSER_NEW_TAB_URL), {
144 triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
146 browser.docShellIsActive = false;
147 browser._urlbarFocused = true;
149 // Make sure the preloaded browser is loaded with desired zoom level
150 let tabURI = Services.io.newURI(window.BROWSER_NEW_TAB_URL);
151 window.FullZoom.onLocationChange(tabURI, false, browser);
153 this.browserCounts[countKey]++;
156 getPreloadedBrowser(window) {
161 // The preloaded browser might be null.
162 let browser = window.gBrowser.preloadedBrowser;
164 // Consume the browser.
165 window.gBrowser.preloadedBrowser = null;
167 // Attach the nsIFormFillController now that we know the browser
168 // will be used. If we do that before and the preloaded browser
169 // won't be consumed until shutdown then we leak a docShell.
170 // Also, we do not need to take care of attaching nsIFormFillControllers
171 // in the case that the browser is remote, as remote browsers take
172 // care of that themselves.
174 let countKey = lazy.PrivateBrowsingUtils.isWindowPrivate(window)
177 this.browserCounts[countKey]--;
178 browser.removeAttribute("preloadedState");
179 browser.setAttribute("autocompletepopup", "PopupAutoComplete");
185 removePreloadedBrowser(window) {
186 let browser = this.getPreloadedBrowser(window);
188 window.gBrowser.getPanel(browser).remove();
193 XPCOMUtils.defineLazyPreferenceGetter(
194 NewTabPagePreloading,
196 "browser.newtab.preload",
199 XPCOMUtils.defineLazyPreferenceGetter(
200 NewTabPagePreloading,
202 "browser.newtabpage.enabled",