Browse Source

refactor: eliminate `DecrementCapturerCount` patch (#35710)

Shelley Vohr 2 years ago
parent
commit
faafcc7f87

+ 5 - 2
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<NativeImage>` - 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])`
 

+ 13 - 3
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<NativeImage>` - 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.

+ 85 - 1
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()
 })

+ 31 - 4
shell/browser/api/electron_api_web_contents.cc

@@ -386,11 +386,13 @@ base::IDMap<WebContents*>& GetAllWebContents() {
   return *s_all_web_contents;
 }
 
-// Called when CapturePage is done.
 void OnCapturePageDone(gin_helper::Promise<gfx::Image> 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<base::TimeDelta> GetCursorBlinkInterval() {
@@ -3174,13 +3176,22 @@ void WebContents::StartDrag(const gin_helper::Dictionary& item,
 }
 
 v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) {
-  gfx::Rect rect;
   gin_helper::Promise<gfx::Image> promise(args->isolate());
   v8::Local<v8::Promise> 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<v8::Promise> 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<v8::Promise> 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;
 

+ 30 - 0
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'));