diff --git a/x-pack/platform/plugins/private/reporting/server/routes/common/request_handler/validator.ts b/x-pack/platform/plugins/private/reporting/server/routes/common/request_handler/validator.ts index e999977dc6bea..da89462a93e4c 100644 --- a/x-pack/platform/plugins/private/reporting/server/routes/common/request_handler/validator.ts +++ b/x-pack/platform/plugins/private/reporting/server/routes/common/request_handler/validator.ts @@ -41,7 +41,8 @@ const timezoneSchema = z.string().refine((val) => validateTimezone(val) === unde const dimensionsSchema = z .object({ - height: z.number().positive().max(14400), + // 16000px height is the maximum screenshot Chrome can make + height: z.number().positive().max(16000), width: z.number().positive().max(14400), }) .strict(); diff --git a/x-pack/platform/plugins/shared/screenshotting/server/layouts/create_layout.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/create_layout.test.ts index d55def96a7273..a28686790ebea 100644 --- a/x-pack/platform/plugins/shared/screenshotting/server/layouts/create_layout.test.ts +++ b/x-pack/platform/plugins/shared/screenshotting/server/layouts/create_layout.test.ts @@ -37,6 +37,7 @@ describe('Create Layout', () => { }, "useReportingBranding": true, "width": 16, + "zoom": 2, } `); }); diff --git a/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.test.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.test.ts index 01e1bbdfa5220..1322e1834fe9b 100644 --- a/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.test.ts +++ b/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.test.ts @@ -58,3 +58,18 @@ it('preserve layout allows customizable selectors', () => { } `); }); + +it('preserve layout use a default zoom of 2', () => { + const testPreserveLayout = new PreserveLayout({ width: 1000, height: 2000 }); + expect(testPreserveLayout.getBrowserZoom()).toBe(2); + expect(testPreserveLayout.getBrowserViewport().height).toBe(4000); +}); + +it('preserve layout caps browser zoom for extremely large screenshots to avoid Chromium artifacts', () => { + // A very tall layout would exceed Chrome limits at zoom=2. + const testPreserveLayout = new PreserveLayout({ width: 1727, height: 15000 }); + + // The zoom should be reduced so that output height stays <= 16000 pixels. + expect(testPreserveLayout.getBrowserZoom()).toBe(1); + expect(testPreserveLayout.getBrowserViewport().height).toBeLessThanOrEqual(16000); +}); diff --git a/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.ts b/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.ts index 79bf7d0f9b852..4ffd25a55aa66 100644 --- a/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.ts +++ b/x-pack/platform/plugins/shared/screenshotting/server/layouts/preserve_layout.ts @@ -12,13 +12,18 @@ import type { Layout } from '.'; import { BaseLayout } from './base_layout'; import type { PageSizeParams, PdfImageSize } from './base_layout'; -// We use a zoom of two to bump up the resolution of the screenshot a bit. -const ZOOM: number = 2; +// We default to a zoom of two to bump up the resolution of the screenshot a bit. +// However, Chromium/Skia has a height limit of 16384px, so for anything larger +// than 8000, we should use a zoom of one. +// https://github.com/puppeteer/puppeteer/issues/359 +const DEFAULT_ZOOM = 2; +const MAX_HEIGHT_PX = 8000; export class PreserveLayout extends BaseLayout implements Layout { public readonly selectors: LayoutSelectorDictionary; public readonly height: number; public readonly width: number; + private readonly zoom: number; private readonly scaledHeight: number; private readonly scaledWidth: number; private imageSize: PdfImageSize = { height: 0, width: 0 }; @@ -27,8 +32,9 @@ export class PreserveLayout extends BaseLayout implements Layout { super('preserve_layout'); this.height = size.height; this.width = size.width; - this.scaledHeight = size.height * ZOOM; - this.scaledWidth = size.width * ZOOM; + this.zoom = this.height <= MAX_HEIGHT_PX ? DEFAULT_ZOOM : 1; + this.scaledHeight = size.height * this.zoom; + this.scaledWidth = size.width * this.zoom; this.selectors = { ...DEFAULT_SELECTORS, ...selectors }; } @@ -46,14 +52,14 @@ export class PreserveLayout extends BaseLayout implements Layout { } public getBrowserZoom() { - return ZOOM; + return this.zoom; } public getViewport() { return { height: this.height, width: this.width, - zoom: ZOOM, + zoom: this.zoom, }; }