@@ -12,24 +12,39 @@ var EXPORTED_SYMBOLS = ["NewTabPagePreloading"];
1212const { XPCOMUtils} = ChromeUtils . import ( "resource://gre/modules/XPCOMUtils.jsm" ) ;
1313const { Services} = ChromeUtils . import ( "resource://gre/modules/Services.jsm" ) ;
1414
15- ChromeUtils . defineModuleGetter ( this , "E10SUtils" , "resource://gre/modules/E10SUtils.jsm" ) ;
15+ XPCOMUtils . defineLazyModuleGetters ( this , {
16+ BrowserWindowTracker : "resource:///modules/BrowserWindowTracker.jsm" ,
17+ E10SUtils : "resource://gre/modules/E10SUtils.jsm" ,
18+ PrivateBrowsingUtils : "resource://gre/modules/PrivateBrowsingUtils.jsm" ,
19+ } ) ;
1620
1721XPCOMUtils . defineLazyServiceGetters ( this , {
1822 gAboutNewTabService : [ "@mozilla.org/browser/aboutnewtab-service;1" , "nsIAboutNewTabService" ] ,
1923} ) ;
2024
2125let NewTabPagePreloading = {
26+ // Maximum number of instances of a given page we'll preload at any time.
27+ // Because we preload about:newtab for normal windows, and about:privatebrowsing
28+ // for private ones, we could have 3 of each.
29+ MAX_COUNT : 3 ,
30+
31+ // How many preloaded tabs we have, across all windows, for the private and non-private
32+ // case:
33+ browserCounts : {
34+ normal : 0 ,
35+ private : 0 ,
36+ } ,
37+
2238 get enabled ( ) {
2339 return this . prefEnabled && this . newTabEnabled &&
2440 ! gAboutNewTabService . overridden ;
2541 } ,
2642
27- maybeCreatePreloadedBrowser ( window ) {
28- if ( ! this . enabled || window . gBrowser . preloadedBrowser ) {
29- return ;
30- }
31-
32- const { gBrowser, gMultiProcessBrowser, BROWSER_NEW_TAB_URL } = window ;
43+ /**
44+ * Create a browser in the right process type.
45+ */
46+ _createBrowser ( win ) {
47+ const { gBrowser, gMultiProcessBrowser, BROWSER_NEW_TAB_URL } = win ;
3348 let remoteType =
3449 E10SUtils . getRemoteTypeForURI ( BROWSER_NEW_TAB_URL , gMultiProcessBrowser ) ;
3550 let browser = gBrowser . createBrowser ( { isPreloadBrowser : true , remoteType } ) ;
@@ -44,16 +59,86 @@ let NewTabPagePreloading = {
4459 // of the preloaded browser until it gets attached to a tab.
4560 browser . webProgress ;
4661 }
62+ return browser ;
63+ } ,
64+
65+ /**
66+ * Move the contents of a preload browser across to a different window.
67+ */
68+ _adoptBrowserFromOtherWindow ( window ) {
69+ let winPrivate = PrivateBrowsingUtils . isWindowPrivate ( window ) ;
70+ // Grab the least-recently-focused window with a preloaded browser:
71+ let oldWin = BrowserWindowTracker . orderedWindows . filter ( w => {
72+ return winPrivate == PrivateBrowsingUtils . isWindowPrivate ( w ) &&
73+ w . gBrowser && w . gBrowser . preloadedBrowser ;
74+ } ) . pop ( ) ;
75+ if ( ! oldWin ) {
76+ return null ;
77+ }
78+ // Don't call getPreloadedBrowser because it'll consume the browser:
79+ let oldBrowser = oldWin . gBrowser . preloadedBrowser ;
80+ oldWin . gBrowser . preloadedBrowser = null ;
81+
82+ let newBrowser = this . _createBrowser ( window ) ;
83+
84+ oldWin . gBrowser . _outerWindowIDBrowserMap . delete ( oldBrowser . outerWindowID ) ;
85+ window . gBrowser . _outerWindowIDBrowserMap . delete ( newBrowser . outerWindowID ) ;
86+
87+ oldBrowser . swapBrowsers ( newBrowser ) ;
88+
89+ // Switch outerWindowIDs for remote browsers.
90+ if ( newBrowser . isRemoteBrowser ) {
91+ newBrowser . _outerWindowID = oldBrowser . _outerWindowID ;
92+ }
93+
94+ window . gBrowser . _outerWindowIDBrowserMap . set ( newBrowser . outerWindowID , newBrowser ) ;
95+ newBrowser . permanentKey = oldBrowser . permanentKey ;
96+
97+ oldWin . gBrowser . getPanel ( oldBrowser ) . remove ( ) ;
98+ return newBrowser ;
99+ } ,
47100
48- browser . loadURI ( BROWSER_NEW_TAB_URL , {
101+ maybeCreatePreloadedBrowser ( window ) {
102+ // If we're not enabled, have already got one, or are in a popup window,
103+ // don't bother creating a preload browser - there's no point.
104+ if ( ! this . enabled || window . gBrowser . preloadedBrowser ||
105+ ! window . toolbar . visible ) {
106+ return ;
107+ }
108+
109+ // Don't bother creating a preload browser if we're not in the top set of windows:
110+ let windowPrivate = PrivateBrowsingUtils . isWindowPrivate ( window ) ;
111+ let countKey = windowPrivate ? "private" : "normal" ;
112+ let topWindows = BrowserWindowTracker . orderedWindows . filter ( w =>
113+ PrivateBrowsingUtils . isWindowPrivate ( w ) == windowPrivate ) ;
114+ if ( topWindows . indexOf ( window ) >= this . MAX_COUNT ) {
115+ return ;
116+ }
117+
118+ // If we're in the top set of windows, and we already have enough preloaded
119+ // tabs, don't create yet another one, just steal an existing one:
120+ if ( this . browserCounts [ countKey ] >= this . MAX_COUNT ) {
121+ let browser = this . _adoptBrowserFromOtherWindow ( window ) ;
122+ // We can potentially get null here if we couldn't actually find another
123+ // browser to adopt from. This can be the case when there's a mix of
124+ // private and non-private windows, for instance.
125+ if ( browser ) {
126+ return ;
127+ }
128+ }
129+
130+ let browser = this . _createBrowser ( window ) ;
131+ browser . loadURI ( window . BROWSER_NEW_TAB_URL , {
49132 triggeringPrincipal : Services . scriptSecurityManager . getSystemPrincipal ( ) ,
50133 } ) ;
51134 browser . docShellIsActive = false ;
52135 browser . _urlbarFocused = true ;
53136
54137 // Make sure the preloaded browser is loaded with desired zoom level
55- let tabURI = Services . io . newURI ( BROWSER_NEW_TAB_URL ) ;
138+ let tabURI = Services . io . newURI ( window . BROWSER_NEW_TAB_URL ) ;
56139 window . FullZoom . onLocationChange ( tabURI , false , browser ) ;
140+
141+ this . browserCounts [ countKey ] ++ ;
57142 } ,
58143
59144 getPreloadedBrowser ( window ) {
@@ -74,6 +159,8 @@ let NewTabPagePreloading = {
74159 // in the case that the browser is remote, as remote browsers take
75160 // care of that themselves.
76161 if ( browser ) {
162+ let countKey = PrivateBrowsingUtils . isWindowPrivate ( window ) ? "private" : "normal" ;
163+ this . browserCounts [ countKey ] -- ;
77164 browser . setAttribute ( "preloadedState" , "consumed" ) ;
78165 browser . setAttribute ( "autocompletepopup" , "PopupAutoComplete" ) ;
79166 }
0 commit comments