Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Screenshotting] Added workaround for webgl driven canvases #131907

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,41 @@ export class HeadlessChromiumDriver {
return !this.page.isClosed();
}

/**
* Despite having "preserveDrawingBuffer": "true" for WebGL driven canvas elements
* we may still get a blank canvas in PDFs. As a further mitigation
* we convert WebGL backed canvases to images and inline replace the canvas element.
* The visual result is identical.
*
* The drawback is that we are mutating the page and so if anything were to interact
* with it after we ran this function it may lead to issues. Ideally, once Chromium
* fixes how PDFs are generated we can remove this code. See:
*
* https://bugs.chromium.org/p/chromium/issues/detail?id=809065
* https://bugs.chromium.org/p/chromium/issues/detail?id=137576
*
* Idea adapted from: https://github.com/puppeteer/puppeteer/issues/1731#issuecomment-864345938
*/
private async workaroundWebGLDrivenCanvases() {
const canvases = await this.page.$$('canvas');
for (const canvas of canvases) {
await canvas.evaluate((thisCanvas: Element) => {
if (
(thisCanvas as HTMLCanvasElement).getContext('webgl') ||
(thisCanvas as HTMLCanvasElement).getContext('webgl2')
) {
const newDiv = document.createElement('div');
const img = document.createElement('img');
img.src = (thisCanvas as HTMLCanvasElement).toDataURL('image/png');
newDiv.appendChild(img);
thisCanvas.parentNode!.replaceChild(newDiv, thisCanvas);
Copy link
Member

@tsullivan tsullivan May 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @elastic/kibana-gis

for awareness: In print-layout PDF reports, we found a bug in Chromium that forces us to capture a screenshot of the map, and then replace the canvas element with the screenshot, before we take the PDF.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This applies to lens charts as well, as Lens canvas tags.

}
});
}
}

async printA4Pdf({ title, logo }: { title: string; logo?: string }): Promise<Buffer> {
await this.workaroundWebGLDrivenCanvases();
return this.page.pdf({
format: 'a4',
preferCSSPageSize: true,
Expand Down