mirror of
https://github.com/microsoft/playwright.git
synced 2025-01-03 00:37:50 +03:00
browser(firefox): move screenshots to browser-side (#15230)
* `clip` option is always passed from the client code * with this change, we can no longer capture screenshot of a blinking caret; the browser-side API doesn't have this capability.
This commit is contained in:
parent
4e46ac2191
commit
e9d66535ba
@ -1,2 +1,2 @@
|
||||
1334
|
||||
Changed: lushnikov@chromium.org Wed Jul 6 01:35:56 MSK 2022
|
||||
1335
|
||||
Changed: lushnikov@chromium.org Wed Jul 6 20:30:28 MSK 2022
|
||||
|
@ -148,7 +148,6 @@ class PageAgent {
|
||||
insertText: this._insertText.bind(this),
|
||||
navigate: this._navigate.bind(this),
|
||||
reload: this._reload.bind(this),
|
||||
screenshot: this._screenshot.bind(this),
|
||||
scrollIntoViewIfNeeded: this._scrollIntoViewIfNeeded.bind(this),
|
||||
setCacheDisabled: this._setCacheDisabled.bind(this),
|
||||
setFileInputFiles: this._setFileInputFiles.bind(this),
|
||||
@ -520,16 +519,6 @@ class PageAgent {
|
||||
return {x: x1, y: y1, width: x2 - x1, height: y2 - y1};
|
||||
}
|
||||
|
||||
async _screenshot({mimeType, clip, omitDeviceScaleFactor}) {
|
||||
const content = this._messageManager.content;
|
||||
if (clip) {
|
||||
const data = takeScreenshot(content, clip.x, clip.y, clip.width, clip.height, mimeType, omitDeviceScaleFactor);
|
||||
return {data};
|
||||
}
|
||||
const data = takeScreenshot(content, content.scrollX, content.scrollY, content.innerWidth, content.innerHeight, mimeType, omitDeviceScaleFactor);
|
||||
return {data};
|
||||
}
|
||||
|
||||
async _dispatchKeyEvent({type, keyCode, code, key, repeat, location, text}) {
|
||||
// key events don't fire if we are dragging.
|
||||
if (this._dragging) {
|
||||
@ -900,31 +889,6 @@ class PageAgent {
|
||||
}
|
||||
}
|
||||
|
||||
function takeScreenshot(win, left, top, width, height, mimeType, omitDeviceScaleFactor) {
|
||||
const MAX_SKIA_DIMENSIONS = 32767;
|
||||
|
||||
// `win.devicePixelRatio` returns a non-overriden value to priveleged code.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1761032
|
||||
// See https://phabricator.services.mozilla.com/D141323
|
||||
const devicePixelRatio = win.browsingContext.overrideDPPX || win.devicePixelRatio;
|
||||
const scale = omitDeviceScaleFactor ? 1 : devicePixelRatio;
|
||||
const canvasWidth = width * scale;
|
||||
const canvasHeight = height * scale;
|
||||
|
||||
if (canvasWidth > MAX_SKIA_DIMENSIONS || canvasHeight > MAX_SKIA_DIMENSIONS)
|
||||
throw new Error('Cannot take screenshot larger than ' + MAX_SKIA_DIMENSIONS);
|
||||
|
||||
const canvas = win.document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
|
||||
canvas.width = canvasWidth;
|
||||
canvas.height = canvasHeight;
|
||||
|
||||
let ctx = canvas.getContext('2d');
|
||||
ctx.scale(scale, scale);
|
||||
ctx.drawWindow(win, left, top, width, height, 'rgb(255,255,255)', ctx.DRAWWINDOW_DRAW_CARET);
|
||||
const dataURL = canvas.toDataURL(mimeType);
|
||||
return dataURL.substring(dataURL.indexOf(',') + 1);
|
||||
};
|
||||
|
||||
var EXPORTED_SYMBOLS = ['PageAgent'];
|
||||
this.PageAgent = PageAgent;
|
||||
|
||||
|
@ -8,6 +8,7 @@ const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {NetworkObserver, PageNetwork} = ChromeUtils.import('chrome://juggler/content/NetworkObserver.js');
|
||||
const {PageTarget} = ChromeUtils.import('chrome://juggler/content/TargetRegistry.js');
|
||||
const {setTimeout} = ChromeUtils.import('resource://gre/modules/Timer.jsm');
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
@ -302,8 +303,51 @@ class PageHandler {
|
||||
return await this._contentPage.send('adoptNode', options);
|
||||
}
|
||||
|
||||
async ['Page.screenshot'](options) {
|
||||
return await this._contentPage.send('screenshot', options);
|
||||
async ['Page.screenshot']({ mimeType, clip, omitDeviceScaleFactor }) {
|
||||
const rect = new DOMRect(clip.x, clip.y, clip.width, clip.height);
|
||||
|
||||
const browsingContext = this._pageTarget.linkedBrowser().browsingContext;
|
||||
// `win.devicePixelRatio` returns a non-overriden value to priveleged code.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1761032
|
||||
// See https://phabricator.services.mozilla.com/D141323
|
||||
const devicePixelRatio = browsingContext.overrideDPPX || this._pageTarget._window.devicePixelRatio;
|
||||
const scale = omitDeviceScaleFactor ? 1 : devicePixelRatio;
|
||||
const canvasWidth = rect.width * scale;
|
||||
const canvasHeight = rect.height * scale;
|
||||
|
||||
const MAX_CANVAS_DIMENSIONS = 32767;
|
||||
const MAX_CANVAS_AREA = 472907776;
|
||||
if (canvasWidth > MAX_CANVAS_DIMENSIONS || canvasHeight > MAX_CANVAS_DIMENSIONS)
|
||||
throw new Error('Cannot take screenshot larger than ' + MAX_CANVAS_DIMENSIONS);
|
||||
if (canvasWidth * canvasHeight > MAX_CANVAS_AREA)
|
||||
throw new Error('Cannot take screenshot with more than ' + MAX_CANVAS_AREA + ' pixels');
|
||||
|
||||
let snapshot;
|
||||
while (!snapshot) {
|
||||
try {
|
||||
//TODO(fission): browsingContext will change in case of cross-group navigation.
|
||||
snapshot = await browsingContext.currentWindowGlobal.drawSnapshot(
|
||||
rect,
|
||||
scale,
|
||||
"rgb(255,255,255)"
|
||||
);
|
||||
} catch (e) {
|
||||
// The currentWindowGlobal.drawSnapshot might throw
|
||||
// NS_ERROR_LOSS_OF_SIGNIFICANT_DATA if called during navigation.
|
||||
// wait a little and re-try.
|
||||
await new Promise(x => setTimeout(x, 50));
|
||||
}
|
||||
}
|
||||
|
||||
const win = browsingContext.topChromeWindow.ownerGlobal;
|
||||
const canvas = win.document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
|
||||
canvas.width = canvasWidth;
|
||||
canvas.height = canvasHeight;
|
||||
let ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(snapshot, 0, 0);
|
||||
snapshot.close();
|
||||
const dataURL = canvas.toDataURL(mimeType);
|
||||
return { data: dataURL.substring(dataURL.indexOf(',') + 1) };
|
||||
}
|
||||
|
||||
async ['Page.getContentQuads'](options) {
|
||||
|
@ -857,7 +857,7 @@ const Page = {
|
||||
'screenshot': {
|
||||
params: {
|
||||
mimeType: t.Enum(['image/png', 'image/jpeg']),
|
||||
clip: t.Optional(pageTypes.Clip),
|
||||
clip: pageTypes.Clip,
|
||||
omitDeviceScaleFactor: t.Optional(t.Boolean),
|
||||
},
|
||||
returns: {
|
||||
|
@ -1,2 +1,2 @@
|
||||
1334
|
||||
Changed: lushnikov@chromium.org Wed Jul 6 00:25:34 MSK 2022
|
||||
1335
|
||||
Changed: lushnikov@chromium.org Wed Jul 6 20:30:28 MSK 2022
|
||||
|
@ -148,7 +148,6 @@ class PageAgent {
|
||||
insertText: this._insertText.bind(this),
|
||||
navigate: this._navigate.bind(this),
|
||||
reload: this._reload.bind(this),
|
||||
screenshot: this._screenshot.bind(this),
|
||||
scrollIntoViewIfNeeded: this._scrollIntoViewIfNeeded.bind(this),
|
||||
setCacheDisabled: this._setCacheDisabled.bind(this),
|
||||
setFileInputFiles: this._setFileInputFiles.bind(this),
|
||||
@ -520,16 +519,6 @@ class PageAgent {
|
||||
return {x: x1, y: y1, width: x2 - x1, height: y2 - y1};
|
||||
}
|
||||
|
||||
async _screenshot({mimeType, clip, omitDeviceScaleFactor}) {
|
||||
const content = this._messageManager.content;
|
||||
if (clip) {
|
||||
const data = takeScreenshot(content, clip.x, clip.y, clip.width, clip.height, mimeType, omitDeviceScaleFactor);
|
||||
return {data};
|
||||
}
|
||||
const data = takeScreenshot(content, content.scrollX, content.scrollY, content.innerWidth, content.innerHeight, mimeType, omitDeviceScaleFactor);
|
||||
return {data};
|
||||
}
|
||||
|
||||
async _dispatchKeyEvent({type, keyCode, code, key, repeat, location, text}) {
|
||||
// key events don't fire if we are dragging.
|
||||
if (this._dragging) {
|
||||
@ -900,31 +889,6 @@ class PageAgent {
|
||||
}
|
||||
}
|
||||
|
||||
function takeScreenshot(win, left, top, width, height, mimeType, omitDeviceScaleFactor) {
|
||||
const MAX_SKIA_DIMENSIONS = 32767;
|
||||
|
||||
// `win.devicePixelRatio` returns a non-overriden value to priveleged code.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1761032
|
||||
// See https://phabricator.services.mozilla.com/D141323
|
||||
const devicePixelRatio = win.browsingContext.overrideDPPX || win.devicePixelRatio;
|
||||
const scale = omitDeviceScaleFactor ? 1 : devicePixelRatio;
|
||||
const canvasWidth = width * scale;
|
||||
const canvasHeight = height * scale;
|
||||
|
||||
if (canvasWidth > MAX_SKIA_DIMENSIONS || canvasHeight > MAX_SKIA_DIMENSIONS)
|
||||
throw new Error('Cannot take screenshot larger than ' + MAX_SKIA_DIMENSIONS);
|
||||
|
||||
const canvas = win.document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
|
||||
canvas.width = canvasWidth;
|
||||
canvas.height = canvasHeight;
|
||||
|
||||
let ctx = canvas.getContext('2d');
|
||||
ctx.scale(scale, scale);
|
||||
ctx.drawWindow(win, left, top, width, height, 'rgb(255,255,255)', ctx.DRAWWINDOW_DRAW_CARET);
|
||||
const dataURL = canvas.toDataURL(mimeType);
|
||||
return dataURL.substring(dataURL.indexOf(',') + 1);
|
||||
};
|
||||
|
||||
var EXPORTED_SYMBOLS = ['PageAgent'];
|
||||
this.PageAgent = PageAgent;
|
||||
|
||||
|
@ -8,6 +8,7 @@ const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {NetworkObserver, PageNetwork} = ChromeUtils.import('chrome://juggler/content/NetworkObserver.js');
|
||||
const {PageTarget} = ChromeUtils.import('chrome://juggler/content/TargetRegistry.js');
|
||||
const {setTimeout} = ChromeUtils.import('resource://gre/modules/Timer.jsm');
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
@ -302,8 +303,51 @@ class PageHandler {
|
||||
return await this._contentPage.send('adoptNode', options);
|
||||
}
|
||||
|
||||
async ['Page.screenshot'](options) {
|
||||
return await this._contentPage.send('screenshot', options);
|
||||
async ['Page.screenshot']({ mimeType, clip, omitDeviceScaleFactor }) {
|
||||
const rect = new DOMRect(clip.x, clip.y, clip.width, clip.height);
|
||||
|
||||
const browsingContext = this._pageTarget.linkedBrowser().browsingContext;
|
||||
// `win.devicePixelRatio` returns a non-overriden value to priveleged code.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1761032
|
||||
// See https://phabricator.services.mozilla.com/D141323
|
||||
const devicePixelRatio = browsingContext.overrideDPPX || this._pageTarget._window.devicePixelRatio;
|
||||
const scale = omitDeviceScaleFactor ? 1 : devicePixelRatio;
|
||||
const canvasWidth = rect.width * scale;
|
||||
const canvasHeight = rect.height * scale;
|
||||
|
||||
const MAX_CANVAS_DIMENSIONS = 32767;
|
||||
const MAX_CANVAS_AREA = 472907776;
|
||||
if (canvasWidth > MAX_CANVAS_DIMENSIONS || canvasHeight > MAX_CANVAS_DIMENSIONS)
|
||||
throw new Error('Cannot take screenshot larger than ' + MAX_CANVAS_DIMENSIONS);
|
||||
if (canvasWidth * canvasHeight > MAX_CANVAS_AREA)
|
||||
throw new Error('Cannot take screenshot with more than ' + MAX_CANVAS_AREA + ' pixels');
|
||||
|
||||
let snapshot;
|
||||
while (!snapshot) {
|
||||
try {
|
||||
//TODO(fission): browsingContext will change in case of cross-group navigation.
|
||||
snapshot = await browsingContext.currentWindowGlobal.drawSnapshot(
|
||||
rect,
|
||||
scale,
|
||||
"rgb(255,255,255)"
|
||||
);
|
||||
} catch (e) {
|
||||
// The currentWindowGlobal.drawSnapshot might throw
|
||||
// NS_ERROR_LOSS_OF_SIGNIFICANT_DATA if called during navigation.
|
||||
// wait a little and re-try.
|
||||
await new Promise(x => setTimeout(x, 50));
|
||||
}
|
||||
}
|
||||
|
||||
const win = browsingContext.topChromeWindow.ownerGlobal;
|
||||
const canvas = win.document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
|
||||
canvas.width = canvasWidth;
|
||||
canvas.height = canvasHeight;
|
||||
let ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(snapshot, 0, 0);
|
||||
snapshot.close();
|
||||
const dataURL = canvas.toDataURL(mimeType);
|
||||
return { data: dataURL.substring(dataURL.indexOf(',') + 1) };
|
||||
}
|
||||
|
||||
async ['Page.getContentQuads'](options) {
|
||||
|
@ -857,7 +857,7 @@ const Page = {
|
||||
'screenshot': {
|
||||
params: {
|
||||
mimeType: t.Enum(['image/png', 'image/jpeg']),
|
||||
clip: t.Optional(pageTypes.Clip),
|
||||
clip: pageTypes.Clip,
|
||||
omitDeviceScaleFactor: t.Optional(t.Boolean),
|
||||
},
|
||||
returns: {
|
||||
|
@ -433,8 +433,6 @@ export class FFPage implements PageDelegate {
|
||||
height: viewportRect!.height,
|
||||
};
|
||||
}
|
||||
// TODO: remove fullPage option from Page.screenshot.
|
||||
// TODO: remove Page.getBoundingBox method.
|
||||
progress.throwIfAborted();
|
||||
const { data } = await this._session.send('Page.screenshot', {
|
||||
mimeType: ('image/' + format) as ('image/png' | 'image/jpeg'),
|
||||
|
Loading…
Reference in New Issue
Block a user