diff options
Diffstat (limited to 'mobile/android/modules/geckoview/GeckoViewNavigation.sys.mjs')
-rw-r--r-- | mobile/android/modules/geckoview/GeckoViewNavigation.sys.mjs | 107 |
1 files changed, 85 insertions, 22 deletions
diff --git a/mobile/android/modules/geckoview/GeckoViewNavigation.sys.mjs b/mobile/android/modules/geckoview/GeckoViewNavigation.sys.mjs index 483f0b01f2..911b08a70e 100644 --- a/mobile/android/modules/geckoview/GeckoViewNavigation.sys.mjs +++ b/mobile/android/modules/geckoview/GeckoViewNavigation.sys.mjs @@ -291,10 +291,10 @@ export class GeckoViewNavigation extends GeckoViewModule { waitAndSetupWindow(aSessionId, aOpenWindowInfo, aName) { if (!aSessionId) { - return Promise.resolve(null); + return Promise.reject(); } - return new Promise(resolve => { + return new Promise((resolve, reject) => { const handler = { observe(aSubject, aTopic) { if ( @@ -318,6 +318,10 @@ export class GeckoViewNavigation extends GeckoViewModule { aSubject.browser.removeAttribute("remoteType"); } Services.obs.removeObserver(handler, "geckoview-window-created"); + if (!aSubject) { + reject(); + return; + } resolve(aSubject); } }, @@ -332,8 +336,45 @@ export class GeckoViewNavigation extends GeckoViewModule { debug`handleNewSession: uri=${aUri && aUri.spec} where=${aWhere} flags=${aFlags}`; + const setupPromise = this.#handleNewSessionAsync( + aUri, + aOpenWindowInfo, + aFlags, + aName + ); + + let browser = undefined; + setupPromise.then( + window => { + browser = window.browser; + }, + () => { + browser = null; + } + ); + + // Wait indefinitely for app to respond with a browser or null + Services.tm.spinEventLoopUntil( + "GeckoViewNavigation.jsm:handleNewSession", + () => this.window.closed || browser !== undefined + ); + return browser || null; + } + + #isNewTab(aWhere) { + return [ + Ci.nsIBrowserDOMWindow.OPEN_NEWTAB, + Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_BACKGROUND, + ].includes(aWhere); + } + + /** + * Similar to handleNewSession. But this returns a promise to wait for new + * browser. + */ + #handleNewSessionAsync(aUri, aOpenWindowInfo, aFlags, aName) { if (!this.enabled) { - return null; + return Promise.reject(); } const newSessionId = Services.uuid @@ -356,30 +397,15 @@ export class GeckoViewNavigation extends GeckoViewModule { aName ); - let browser = undefined; - this.eventDispatcher + return this.eventDispatcher .sendRequestForResult(message) .then(didOpenSession => { if (!didOpenSession) { + // New session cannot be opened, so we should throw NS_ERROR_ABORT. return Promise.reject(); } return setupPromise; - }) - .then( - window => { - browser = window.browser; - }, - () => { - browser = null; - } - ); - - // Wait indefinitely for app to respond with a browser or null - Services.tm.spinEventLoopUntil( - "GeckoViewNavigation.sys.mjs:handleNewSession", - () => this.window.closed || browser !== undefined - ); - return browser || null; + }); } // nsIBrowserDOMWindow. @@ -393,6 +419,11 @@ export class GeckoViewNavigation extends GeckoViewModule { debug`createContentWindow: uri=${aUri && aUri.spec} where=${aWhere} flags=${aFlags}`; + if (!this.enabled) { + Components.returnCode = Cr.NS_ERROR_ABORT; + return null; + } + if ( lazy.LoadURIDelegate.load( this.window, @@ -408,13 +439,45 @@ export class GeckoViewNavigation extends GeckoViewModule { return null; } - const browser = this.handleNewSession( + const newTab = this.#isNewTab(aWhere); + const promise = this.#handleNewSessionAsync( aUri, aOpenWindowInfo, aWhere, aFlags, null ); + + // Actually, GeckoView's createContentWindow always creates new window even + // if OPEN_NEWTAB. So the browsing context will be observed via + // nsFrameLoader. + if (aOpenWindowInfo && !newTab) { + promise.catch(() => { + aOpenWindowInfo.cancel(); + }); + // If nsIOpenWindowInfo isn't null, caller should use the callback. + // Also, nsIWindowProvider.provideWindow doesn't use callback, if new + // tab option, we have to return browsing context instead of async. + return null; + } + + let browser = undefined; + promise.then( + window => { + browser = window.browser; + }, + () => { + browser = null; + } + ); + + // Wait indefinitely for app to respond with a browser or null. + // if browser is null, return error. + Services.tm.spinEventLoopUntil( + "GeckoViewNavigation.sys.mjs:createContentWindow", + () => this.window.closed || browser !== undefined + ); + if (!browser) { Components.returnCode = Cr.NS_ERROR_ABORT; return null; |