diff --git a/packages/playwright-core/src/server/webkit/wkPage.ts b/packages/playwright-core/src/server/webkit/wkPage.ts index 4c7c54a66b..9af4813b1b 100644 --- a/packages/playwright-core/src/server/webkit/wkPage.ts +++ b/packages/playwright-core/src/server/webkit/wkPage.ts @@ -829,9 +829,23 @@ export class WKPage implements PageDelegate { this._recordingVideoFile = null; } + private validateScreenshotDimension(side: number, omitDeviceScaleFactor: boolean) { + // Cairo based implementations (Linux and Windows) have hard limit of 32767 + // (see https://github.com/microsoft/playwright/issues/16727). + if (process.platform === 'darwin') + return; + if (!omitDeviceScaleFactor && this._page._browserContext._options.deviceScaleFactor) + side = Math.ceil(side * this._page._browserContext._options.deviceScaleFactor); + if (side > 32767) + throw new Error('Cannot take screenshot larger than 32767 pixels on any dimension'); + } + async takeScreenshot(progress: Progress, format: string, documentRect: types.Rect | undefined, viewportRect: types.Rect | undefined, quality: number | undefined, fitsViewport: boolean, scale: 'css' | 'device'): Promise { const rect = (documentRect || viewportRect)!; - const result = await this._session.send('Page.snapshotRect', { ...rect, coordinateSystem: documentRect ? 'Page' : 'Viewport', omitDeviceScaleFactor: scale === 'css' }); + const omitDeviceScaleFactor = scale === 'css'; + this.validateScreenshotDimension(rect.width, omitDeviceScaleFactor); + this.validateScreenshotDimension(rect.height, omitDeviceScaleFactor); + const result = await this._session.send('Page.snapshotRect', { ...rect, coordinateSystem: documentRect ? 'Page' : 'Viewport', omitDeviceScaleFactor }); const prefix = 'data:image/png;base64,'; let buffer = Buffer.from(result.dataURL.substr(prefix.length), 'base64'); if (format === 'jpeg') diff --git a/tests/library/screenshot.spec.ts b/tests/library/screenshot.spec.ts index fb70b50ae3..87e6f7da17 100644 --- a/tests/library/screenshot.spec.ts +++ b/tests/library/screenshot.spec.ts @@ -108,6 +108,27 @@ browserTest.describe('page screenshot', () => { await context.close(); }); + browserTest('should throw if screenshot size is too large with device scale factor', async ({ browser, browserName, isMac }) => { + browserTest.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/16727' }); + const context = await browser.newContext({ viewport: { width: 500, height: 500 }, deviceScaleFactor: 2 }); + const page = await context.newPage(); + { + await page.setContent(`
`); + const result = await page.screenshot({ fullPage: true }); + expect(result).toBeTruthy(); + } + { + await page.setContent(`
`); + const exception = await page.screenshot({ fullPage: true }).catch(e => e); + if (browserName === 'firefox' || (browserName === 'webkit' && !isMac)) + expect(exception.message).toContain('Cannot take screenshot larger than 32767'); + + const image = await page.screenshot({ fullPage: true, scale: 'css' }); + expect(image).toBeTruthy(); + } + await context.close(); + }); + browserTest('should work with large size', async ({ browserName, headless, platform, contextFactory }) => { browserTest.fixme(browserName === 'chromium' && !headless && platform === 'linux', 'Chromium has gpu problems on linux with large screnshots'); browserTest.slow(true, 'Large screenshot is slow'); diff --git a/tests/page/page-screenshot.spec.ts b/tests/page/page-screenshot.spec.ts index b81d6d4165..8e08aa6528 100644 --- a/tests/page/page-screenshot.spec.ts +++ b/tests/page/page-screenshot.spec.ts @@ -814,3 +814,17 @@ it.describe('page screenshot animations', () => { }); }); +it('should throw if screenshot size is too large', async ({ page, browserName, isMac }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/16727' }); + { + await page.setContent(`
`); + const result = await page.screenshot({ fullPage: true }); + expect(result).toBeTruthy(); + } + { + await page.setContent(`
`); + const exception = await page.screenshot({ fullPage: true }).catch(e => e); + if (browserName === 'firefox' || (browserName === 'webkit' && !isMac)) + expect(exception.message).toContain('Cannot take screenshot larger than 32767'); + } +});