diff --git a/browser_patches/firefox/BUILD_NUMBER b/browser_patches/firefox/BUILD_NUMBER index 05d04bfb36..846e5ce449 100644 --- a/browser_patches/firefox/BUILD_NUMBER +++ b/browser_patches/firefox/BUILD_NUMBER @@ -1,2 +1,2 @@ -1179 -Changed: lushnikov@chromium.org Fri Oct 2 03:14:15 PDT 2020 +1180 +Changed: dgozman@gmail.com Fri Oct 2 09:36:06 PDT 2020 diff --git a/browser_patches/firefox/juggler/TargetRegistry.js b/browser_patches/firefox/juggler/TargetRegistry.js index 7cb6660f6b..b3e2e91886 100644 --- a/browser_patches/firefox/juggler/TargetRegistry.js +++ b/browser_patches/firefox/juggler/TargetRegistry.js @@ -10,6 +10,7 @@ const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm"); const {NetUtil} = ChromeUtils.import('resource://gre/modules/NetUtil.jsm'); const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); +const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); const helper = new Helper(); @@ -350,6 +351,7 @@ class PageTarget { this._openerId = opener ? opener.id() : undefined; this._channel = SimpleChannel.createForMessageManager(`browser::page[${this._targetId}]`, this._linkedBrowser.messageManager); this._channelIds = new Set(); + this._screencastInfo = undefined; const navigationListener = { QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), @@ -454,6 +456,50 @@ class PageTarget { return await this._channel.connect('').send('hasFailedToOverrideTimezone').catch(e => true); } + async startVideoRecording({width, height, scale, dir}) { + // On Mac the window may not yet be visible when TargetCreated and its + // NSWindow.windowNumber may be -1, so we wait until the window is known + // to be initialized and visible. + await this.windowReady(); + const file = OS.Path.join(dir, helper.generateId() + '.webm'); + if (width < 10 || width > 10000 || height < 10 || height > 10000) + throw new Error("Invalid size"); + if (scale && (scale <= 0 || scale > 1)) + throw new Error("Unsupported scale"); + + const screencast = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService); + const docShell = this._gBrowser.ownerGlobal.docShell; + // Exclude address bar and navigation control from the video. + const rect = this.linkedBrowser().getBoundingClientRect(); + const devicePixelRatio = this._window.devicePixelRatio; + const videoSessionId = screencast.startVideoRecording(docShell, file, width, height, scale || 0, devicePixelRatio * rect.top); + this._screencastInfo = { videoSessionId, file }; + this.emit('screencastStarted'); + } + + async stopVideoRecording() { + if (!this._screencastInfo) + throw new Error('No video recording in progress'); + const screencastInfo = this._screencastInfo; + this._screencastInfo = undefined; + const screencast = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService); + const result = new Promise(resolve => + Services.obs.addObserver(function onStopped(subject, topic, data) { + if (screencastInfo.videoSessionId != data) + return; + + Services.obs.removeObserver(onStopped, 'juggler-screencast-stopped'); + resolve(); + }, 'juggler-screencast-stopped') + ); + screencast.stopVideoRecording(screencastInfo.videoSessionId); + return result; + } + + screencastInfo() { + return this._screencastInfo; + } + dispose() { this._disposed = true; this._browserContext.pages.delete(this); @@ -673,8 +719,14 @@ class BrowserContext { return result; } - setScreencastOptions(options) { + async setScreencastOptions(options) { this.screencastOptions = options; + if (!options) + return; + const promises = []; + for (const page of this.pages) + promises.push(page.startVideoRecording(options)); + await Promise.all(promises); } } diff --git a/browser_patches/firefox/juggler/protocol/PageHandler.js b/browser_patches/firefox/juggler/protocol/PageHandler.js index 9bdb0d064d..ef853c62d9 100644 --- a/browser_patches/firefox/juggler/protocol/PageHandler.js +++ b/browser_patches/firefox/juggler/protocol/PageHandler.js @@ -6,7 +6,6 @@ const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); -const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm"); const Cc = Components.classes; const Ci = Components.interfaces; @@ -91,7 +90,6 @@ class PageHandler { this._dialogs = new Map(); this._enabled = false; - this._videoSessionId = -1; } _onWorkerCreated({workerId, frameId, url}) { @@ -132,24 +130,23 @@ class PageHandler { helper.on(this._pageTarget, 'crashed', () => { this._session.emitEvent('Page.crashed', {}); }), + helper.on(this._pageTarget, 'screencastStarted', () => { + const info = this._pageTarget.screencastInfo(); + this._session.emitEvent('Page.screencastStarted', { screencastId: '' + info.videoSessionId, file: info.file }); + }), ]); const options = this._pageTarget.browserContext().screencastOptions; - if (options) { - const file = OS.Path.join(options.dir, helper.generateId() + '.webm'); - // On Mac the window may not yet be visible when TargetCreated and its - // NSWindow.windowNumber may be -1, so we wait until the window is known - // to be initialized and visible. - await this._pageTarget.windowReady(); - await this.startVideoRecording(Object.assign({file}, options)); - } + if (options) + await this._pageTarget.startVideoRecording(options); } async dispose() { this._contentPage.dispose(); helper.removeListeners(this._eventListeners); - if (this._videoSessionId !== -1) - await this.stopVideoRecording().catch(e => dump(`stopVideoRecording failed:\n${e}\n`)); + + if (this._pageTarget.screencastInfo()) + await this._pageTarget.stopVideoRecording().catch(e => dump(`stopVideoRecording failed:\n${e}\n`)); } async setViewportSize({viewportSize}) { @@ -303,38 +300,8 @@ class PageHandler { return await worker.sendMessage(JSON.parse(message)); } - startVideoRecording({file, width, height, scale}) { - if (width < 10 || width > 10000 || height < 10 || height > 10000) - throw new Error("Invalid size"); - if (scale && (scale <= 0 || scale > 1)) - throw new Error("Unsupported scale"); - - const screencast = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService); - const docShell = this._pageTarget._gBrowser.ownerGlobal.docShell; - // Exclude address bar and navigation control from the video. - const rect = this._pageTarget.linkedBrowser().getBoundingClientRect(); - const devicePixelRatio = this._pageTarget._window.devicePixelRatio; - this._videoSessionId = screencast.startVideoRecording(docShell, file, width, height, scale || 0, devicePixelRatio * rect.top); - this._session.emitEvent('Page.screencastStarted', {screencastId: '' + this._videoSessionId, file}); - } - async stopVideoRecording() { - if (this._videoSessionId === -1) - throw new Error('No video recording in progress'); - const videoSessionId = this._videoSessionId; - this._videoSessionId = -1; - const screencast = Cc['@mozilla.org/juggler/screencast;1'].getService(Ci.nsIScreencastService); - const result = new Promise(resolve => - Services.obs.addObserver(function onStopped(subject, topic, data) { - if (videoSessionId != data) - return; - - Services.obs.removeObserver(onStopped, 'juggler-screencast-stopped'); - resolve(); - }, 'juggler-screencast-stopped') - ); - screencast.stopVideoRecording(videoSessionId); - return result; + await this._pageTarget.stopVideoRecording(); } }