From faafcc7f873f535a3637e54635f262f237071059 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 5 Oct 2022 10:51:33 -0700 Subject: [PATCH] refactor: eliminate `DecrementCapturerCount` patch (#35710) --- docs/api/browser-window.md | 7 +- docs/api/web-contents.md | 16 +++- docs/breaking-changes.md | 86 ++++++++++++++++++- .../browser/api/electron_api_web_contents.cc | 35 +++++++- spec/api-browser-window-spec.ts | 30 +++++++ 5 files changed, 164 insertions(+), 10 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 859b1876a1..5f21805d87 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -1437,13 +1437,16 @@ Returns `boolean` - Whether the window's document has been edited. #### `win.blurWebView()` -#### `win.capturePage([rect])` +#### `win.capturePage([rect, opts])` * `rect` [Rectangle](structures/rectangle.md) (optional) - The bounds to capture +* `opts` Object (optional) + * `stayHidden` boolean (optional) - Keep the page hidden instead of visible. Default is `false`. + * `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. Default is `false`. Returns `Promise` - Resolves with a [NativeImage](native-image.md) -Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty. +Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. If the page is not visible, `rect` may be empty. The page is considered visible when its browser window is hidden and the capturer count is non-zero. If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true. #### `win.loadURL(url[, options])` diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 17084a7c7c..b481bf055e 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1338,20 +1338,25 @@ const requestId = webContents.findInPage('api') console.log(requestId) ``` -#### `contents.capturePage([rect])` +#### `contents.capturePage([rect, opts])` * `rect` [Rectangle](structures/rectangle.md) (optional) - The area of the page to be captured. +* `opts` Object (optional) + * `stayHidden` boolean (optional) - Keep the page hidden instead of visible. Default is `false`. + * `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. Default is `false`. Returns `Promise` - Resolves with a [NativeImage](native-image.md) Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page. +The page is considered visible when its browser window is hidden and the capturer count is non-zero. +If you would like the page to stay hidden, you should ensure that `stayHidden` is set to true. #### `contents.isBeingCaptured()` Returns `boolean` - Whether this page is being captured. It returns true when the capturer count is large then 0. -#### `contents.incrementCapturerCount([size, stayHidden, stayAwake])` +#### `contents.incrementCapturerCount([size, stayHidden, stayAwake])` _Deprecated_ * `size` [Size](structures/size.md) (optional) - The preferred size for the capturer. * `stayHidden` boolean (optional) - Keep the page hidden instead of visible. @@ -1362,7 +1367,9 @@ hidden and the capturer count is non-zero. If you would like the page to stay hi This also affects the Page Visibility API. -#### `contents.decrementCapturerCount([stayHidden, stayAwake])` +**Deprecated:** This API's functionality is now handled automatically within `contents.capturePage()`. See [breaking changes](../breaking-changes.md). + +#### `contents.decrementCapturerCount([stayHidden, stayAwake])` _Deprecated_ * `stayHidden` boolean (optional) - Keep the page in hidden state instead of visible. * `stayAwake` boolean (optional) - Keep the system awake instead of allowing it to sleep. @@ -1371,6 +1378,9 @@ Decrease the capturer count by one. The page will be set to hidden or occluded s browser window is hidden or occluded and the capturer count reaches zero. If you want to decrease the hidden capturer count instead you should set `stayHidden` to true. +**Deprecated:** This API's functionality is now handled automatically within `contents.capturePage()`. +See [breaking changes](../breaking-changes.md). + #### `contents.getPrinters()` _Deprecated_ Get the system printer list. diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index b923254f6a..4db4fd7862 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -38,14 +38,98 @@ win.webContents.on('input-event', (_, event) => { }) ``` +### Removed: `webContents.incrementCapturerCount(stayHidden, stayAwake)` + +The `webContents.incrementCapturerCount(stayHidden, stayAwake)` function has been removed. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + +### Removed: `webContents.decrementCapturerCount(stayHidden, stayAwake)` + +The `webContents.decrementCapturerCount(stayHidden, stayAwake)` function has been removed. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + ## Planned Breaking API Changes (22.0) +### Deprecated: `webContents.incrementCapturerCount(stayHidden, stayAwake)` + +`webContents.incrementCapturerCount(stayHidden, stayAwake)` has been deprecated. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + +### Removed: `webContents.decrementCapturerCount(stayHidden, stayAwake)` + +`webContents.decrementCapturerCount(stayHidden, stayAwake)` has been deprecated. +It is now automatically handled by `webContents.capturePage` when a page capture completes. + +```js +const w = new BrowserWindow({ show: false }) + +// Removed in Electron 23 +w.webContents.incrementCapturerCount() +w.capturePage().then(image => { + console.log(image.toDataURL()) + w.webContents.decrementCapturerCount() +}) + +// Replace with +w.capturePage().then(image => { + console.log(image.toDataURL()) +}) +``` + ### Removed: WebContents `new-window` event The `new-window` event of WebContents has been removed. It is replaced by [`webContents.setWindowOpenHandler()`](api/web-contents.md#contentssetwindowopenhandlerhandler). ```js -// Removed in Electron 21 +// Removed in Electron 22 webContents.on('new-window', (event) => { event.preventDefault() }) diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index f3c9ca481a..5fef7db997 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -386,11 +386,13 @@ base::IDMap& GetAllWebContents() { return *s_all_web_contents; } -// Called when CapturePage is done. void OnCapturePageDone(gin_helper::Promise promise, + base::ScopedClosureRunner capture_handle, const SkBitmap& bitmap) { // Hack to enable transparency in captured image promise.Resolve(gfx::Image::CreateFrom1xBitmap(bitmap)); + + capture_handle.RunAndReset(); } absl::optional GetCursorBlinkInterval() { @@ -3174,13 +3176,22 @@ void WebContents::StartDrag(const gin_helper::Dictionary& item, } v8::Local WebContents::CapturePage(gin::Arguments* args) { - gfx::Rect rect; gin_helper::Promise promise(args->isolate()); v8::Local handle = promise.GetHandle(); - // get rect arguments if they exist + gfx::Rect rect; args->GetNext(&rect); + bool stay_hidden = false; + bool stay_awake = false; + if (args && args->Length() == 2) { + gin_helper::Dictionary options; + if (args->GetNext(&options)) { + options.Get("stayHidden", &stay_hidden); + options.Get("stayAwake", &stay_awake); + } + } + auto* const view = web_contents()->GetRenderWidgetHostView(); if (!view) { promise.Resolve(gfx::Image()); @@ -3199,6 +3210,9 @@ v8::Local WebContents::CapturePage(gin::Arguments* args) { } #endif // BUILDFLAG(IS_MAC) + auto capture_handle = web_contents()->IncrementCapturerCount( + rect.size(), stay_hidden, stay_awake); + // Capture full page if user doesn't specify a |rect|. const gfx::Size view_size = rect.IsEmpty() ? view->GetViewBounds().size() : rect.size(); @@ -3215,11 +3229,18 @@ v8::Local WebContents::CapturePage(gin::Arguments* args) { bitmap_size = gfx::ScaleToCeiledSize(view_size, scale); view->CopyFromSurface(gfx::Rect(rect.origin(), view_size), bitmap_size, - base::BindOnce(&OnCapturePageDone, std::move(promise))); + base::BindOnce(&OnCapturePageDone, std::move(promise), + std::move(capture_handle))); return handle; } +// TODO(codebytere): remove in Electron v23. void WebContents::IncrementCapturerCount(gin::Arguments* args) { + EmitWarning(node::Environment::GetCurrent(args->isolate()), + "webContents.incrementCapturerCount() is deprecated and will be " + "removed in v23", + "electron"); + gfx::Size size; bool stay_hidden = false; bool stay_awake = false; @@ -3236,7 +3257,13 @@ void WebContents::IncrementCapturerCount(gin::Arguments* args) { .Release(); } +// TODO(codebytere): remove in Electron v23. void WebContents::DecrementCapturerCount(gin::Arguments* args) { + EmitWarning(node::Environment::GetCurrent(args->isolate()), + "webContents.decrementCapturerCount() is deprecated and will be " + "removed in v23", + "electron"); + bool stay_hidden = false; bool stay_awake = false; diff --git a/spec/api-browser-window-spec.ts b/spec/api-browser-window-spec.ts index de2330b923..943200c6ac 100644 --- a/spec/api-browser-window-spec.ts +++ b/spec/api-browser-window-spec.ts @@ -1737,6 +1737,36 @@ describe('BrowserWindow module', () => { expect(image.isEmpty()).to.equal(true); }); + ifit(process.platform === 'darwin')('honors the stayHidden argument', async () => { + const w = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + contextIsolation: false + } + }); + + w.loadFile(path.join(fixtures, 'pages', 'visibilitychange.html')); + + { + const [, visibilityState, hidden] = await emittedOnce(ipcMain, 'pong'); + expect(visibilityState).to.equal('visible'); + expect(hidden).to.be.false('hidden'); + } + + w.hide(); + + { + const [, visibilityState, hidden] = await emittedOnce(ipcMain, 'pong'); + expect(visibilityState).to.equal('hidden'); + expect(hidden).to.be.true('hidden'); + } + + await w.capturePage({ x: 0, y: 0, width: 0, height: 0 }, { stayHidden: true }); + + const visible = await w.webContents.executeJavaScript('document.visibilityState'); + expect(visible).to.equal('hidden'); + }); + it('resolves after the window is hidden', async () => { const w = new BrowserWindow({ show: false }); w.loadFile(path.join(fixtures, 'pages', 'a.html'));