diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index 1919f3066089..a2fb9d94ab9d 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -469,9 +469,16 @@ base::IDMap& GetAllWebContents() { void OnCapturePageDone(gin_helper::Promise promise, base::ScopedClosureRunner capture_handle, const SkBitmap& bitmap) { + auto ui_task_runner = content::GetUIThreadTaskRunner({}); + if (!ui_task_runner->RunsTasksInCurrentSequence()) { + ui_task_runner->PostTask( + FROM_HERE, base::BindOnce(&OnCapturePageDone, std::move(promise), + std::move(capture_handle), bitmap)); + return; + } + // Hack to enable transparency in captured image promise.Resolve(gfx::Image::CreateFrom1xBitmap(bitmap)); - capture_handle.RunAndReset(); } @@ -3462,22 +3469,16 @@ v8::Local WebContents::CapturePage(gin::Arguments* args) { } auto* const view = web_contents()->GetRenderWidgetHostView(); - if (!view) { + if (!view || view->GetViewBounds().size().IsEmpty()) { promise.Resolve(gfx::Image()); return handle; } -#if !BUILDFLAG(IS_MAC) - // If the view's renderer is suspended this may fail on Windows/Linux - - // bail if so. See CopyFromSurface in - // content/public/browser/render_widget_host_view.h. - auto* rfh = web_contents()->GetPrimaryMainFrame(); - if (rfh && - rfh->GetVisibilityState() == blink::mojom::PageVisibilityState::kHidden) { - promise.Resolve(gfx::Image()); + if (!view->IsSurfaceAvailableForCopy()) { + promise.RejectWithErrorMessage( + "Current display surface not available for capture"); return handle; } -#endif // BUILDFLAG(IS_MAC) auto capture_handle = web_contents()->IncrementCapturerCount( rect.size(), stay_hidden, stay_awake); diff --git a/spec/api-browser-window-spec.ts b/spec/api-browser-window-spec.ts index 2fb6cb00086f..41986ed7ae43 100644 --- a/spec/api-browser-window-spec.ts +++ b/spec/api-browser-window-spec.ts @@ -2224,7 +2224,22 @@ describe('BrowserWindow module', () => { expect(visible).to.equal('hidden'); }); - it('resolves after the window is hidden', async () => { + it('resolves when the window is occluded', async () => { + const w1 = new BrowserWindow({ show: false }); + w1.loadFile(path.join(fixtures, 'pages', 'a.html')); + await once(w1, 'ready-to-show'); + w1.show(); + + const w2 = new BrowserWindow({ show: false }); + w2.loadFile(path.join(fixtures, 'pages', 'a.html')); + await once(w2, 'ready-to-show'); + w2.show(); + + const visibleImage = await w1.capturePage(); + expect(visibleImage.isEmpty()).to.equal(false); + }); + + it('resolves when the window is not visible', async () => { const w = new BrowserWindow({ show: false }); w.loadFile(path.join(fixtures, 'pages', 'a.html')); await once(w, 'ready-to-show'); @@ -2233,21 +2248,10 @@ describe('BrowserWindow module', () => { const visibleImage = await w.capturePage(); expect(visibleImage.isEmpty()).to.equal(false); - w.hide(); + w.minimize(); const hiddenImage = await w.capturePage(); - const isEmpty = process.platform !== 'darwin'; - expect(hiddenImage.isEmpty()).to.equal(isEmpty); - }); - - it('resolves after the window is hidden and capturer count is non-zero', async () => { - const w = new BrowserWindow({ show: false }); - w.webContents.setBackgroundThrottling(false); - w.loadFile(path.join(fixtures, 'pages', 'a.html')); - await once(w, 'ready-to-show'); - - const image = await w.capturePage(); - expect(image.isEmpty()).to.equal(false); + expect(hiddenImage.isEmpty()).to.equal(false); }); it('preserves transparency', async () => {