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 var EXPORTED_SYMBOLS = ["NewTabPagePreloading"];
12 const { XPCOMUtils } = ChromeUtils.import(
13 "resource://gre/modules/XPCOMUtils.jsm"
15 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
17 XPCOMUtils.defineLazyModuleGetters(this, {
18 AboutNewTab: "resource:///modules/AboutNewTab.jsm",
19 BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
20 E10SUtils: "resource://gre/modules/E10SUtils.jsm",
21 PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
24 let NewTabPagePreloading = {
25 // Maximum number of instances of a given page we'll preload at any time.
26 // Because we preload about:newtab for normal windows, and about:privatebrowsing
27 // for private ones, we could have 3 of each.
30 // How many preloaded tabs we have, across all windows, for the private and non-private
39 this.prefEnabled && this.newTabEnabled && !AboutNewTab.newTabURLOverridden
44 * Create a browser in the right process type.
54 let oa = E10SUtils.predictOriginAttributes({ window: win });
56 let remoteType = E10SUtils.getRemoteTypeForURI(
60 E10SUtils.DEFAULT_REMOTE_TYPE,
64 let browser = gBrowser.createBrowser({
65 isPreloadBrowser: true,
68 gBrowser.preloadedBrowser = browser;
70 let panel = gBrowser.getPanel(browser);
71 gBrowser.tabpanels.appendChild(panel);
77 * Move the contents of a preload browser across to a different window.
79 _adoptBrowserFromOtherWindow(window) {
80 let winPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
81 // Grab the least-recently-focused window with a preloaded browser:
82 let oldWin = BrowserWindowTracker.orderedWindows
85 winPrivate == PrivateBrowsingUtils.isWindowPrivate(w) &&
87 w.gBrowser.preloadedBrowser
94 // Don't call getPreloadedBrowser because it'll consume the browser:
95 let oldBrowser = oldWin.gBrowser.preloadedBrowser;
96 oldWin.gBrowser.preloadedBrowser = null;
98 let newBrowser = this._createBrowser(window);
100 oldBrowser.swapBrowsers(newBrowser);
102 newBrowser.permanentKey = oldBrowser.permanentKey;
104 oldWin.gBrowser.getPanel(oldBrowser).remove();
108 maybeCreatePreloadedBrowser(window) {
109 // If we're not enabled, have already got one, are in a popup window, or the
110 // window is minimized / occluded, don't bother creating a preload browser -
114 window.gBrowser.preloadedBrowser ||
115 !window.toolbar.visible ||
116 window.windowState == window.STATE_MINIMIZED ||
117 window.isFullyOccluded
122 // Don't bother creating a preload browser if we're not in the top set of windows:
123 let windowPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
124 let countKey = windowPrivate ? "private" : "normal";
125 let topWindows = BrowserWindowTracker.orderedWindows.filter(
126 w => PrivateBrowsingUtils.isWindowPrivate(w) == windowPrivate
128 if (topWindows.indexOf(window) >= this.MAX_COUNT) {
132 // If we're in the top set of windows, and we already have enough preloaded
133 // tabs, don't create yet another one, just steal an existing one:
134 if (this.browserCounts[countKey] >= this.MAX_COUNT) {
135 let browser = this._adoptBrowserFromOtherWindow(window);
136 // We can potentially get null here if we couldn't actually find another
137 // browser to adopt from. This can be the case when there's a mix of
138 // private and non-private windows, for instance.
144 let browser = this._createBrowser(window);
145 browser.loadURI(window.BROWSER_NEW_TAB_URL, {
146 triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
148 browser.docShellIsActive = false;
149 browser._urlbarFocused = true;
151 // Make sure the preloaded browser is loaded with desired zoom level
152 let tabURI = Services.io.newURI(window.BROWSER_NEW_TAB_URL);
153 window.FullZoom.onLocationChange(tabURI, false, browser);
155 this.browserCounts[countKey]++;
158 getPreloadedBrowser(window) {
163 // The preloaded browser might be null.
164 let browser = window.gBrowser.preloadedBrowser;
166 // Consume the browser.
167 window.gBrowser.preloadedBrowser = null;
169 // Attach the nsIFormFillController now that we know the browser
170 // will be used. If we do that before and the preloaded browser
171 // won't be consumed until shutdown then we leak a docShell.
172 // Also, we do not need to take care of attaching nsIFormFillControllers
173 // in the case that the browser is remote, as remote browsers take
174 // care of that themselves.
176 let countKey = PrivateBrowsingUtils.isWindowPrivate(window)
179 this.browserCounts[countKey]--;
180 browser.setAttribute("preloadedState", "consumed");
181 browser.setAttribute("autocompletepopup", "PopupAutoComplete");
187 removePreloadedBrowser(window) {
188 let browser = this.getPreloadedBrowser(window);
190 window.gBrowser.getPanel(browser).remove();
195 XPCOMUtils.defineLazyPreferenceGetter(
196 NewTabPagePreloading,
198 "browser.newtab.preload",
201 XPCOMUtils.defineLazyPreferenceGetter(
202 NewTabPagePreloading,
204 "browser.newtabpage.enabled",