Skip to content

Commit

Permalink
core(full-page-screenshot): get the MAX_TEXTURE_SIZE from the browser (
Browse files Browse the repository at this point in the history
  • Loading branch information
paulirish authored Jan 13, 2021
1 parent 69ef261 commit 3a820a3
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
23 changes: 18 additions & 5 deletions lighthouse-core/gather/gatherers/full-page-screenshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
const Gatherer = require('./gatherer.js');
const pageFunctions = require('../../lib/page-functions.js');

/** @typedef {import('../driver.js')} Driver */

// JPEG quality setting
// Exploration and examples of reports using different quality settings: https://docs.google.com/document/d/1ZSffucIca9XDW2eEwfoevrk-OTl7WQFeMf0CgeJAA8M/edit#
const FULL_PAGE_SCREENSHOT_QUALITY = 30;
// Maximum screenshot height in Chrome https://bugs.chromium.org/p/chromium/issues/detail?id=770769
const MAX_SCREENSHOT_HEIGHT = 16384;

/**
* @param {string} str
Expand All @@ -24,12 +24,26 @@ function snakeCaseToCamelCase(str) {
}

class FullPageScreenshot extends Gatherer {
/**
* @param {Driver} driver
* @return {Promise<number>}
* @see https://bugs.chromium.org/p/chromium/issues/detail?id=770769
*/
async getMaxScreenshotHeight(driver) {
return await driver.evaluate(pageFunctions.getMaxTextureSize, {
args: [],
useIsolation: true,
deps: [],
});
}

/**
* @param {LH.Gatherer.PassContext} passContext
* @return {Promise<LH.Artifacts.FullPageScreenshot['screenshot']>}
*/
async _takeScreenshot(passContext) {
const driver = passContext.driver;
const maxScreenshotHeight = await this.getMaxScreenshotHeight(driver);
const metrics = await driver.sendCommand('Page.getLayoutMetrics');

// Width should match emulated width, without considering content overhang.
Expand All @@ -38,8 +52,8 @@ class FullPageScreenshot extends Gatherer {
// Note: If the page is zoomed, many assumptions fail.
//
// Height should be as tall as the content. So we use contentSize.height
const width = Math.min(metrics.layoutViewport.clientWidth, MAX_SCREENSHOT_HEIGHT);
const height = Math.min(metrics.contentSize.height, MAX_SCREENSHOT_HEIGHT);
const width = Math.min(metrics.layoutViewport.clientWidth, maxScreenshotHeight);
const height = Math.min(metrics.contentSize.height, maxScreenshotHeight);

await driver.sendCommand('Emulation.setDeviceMetricsOverride', {
// If we're gathering with mobile screenEmulation on (overlay scrollbars, etc), continue to use that for this screenshot.
Expand Down Expand Up @@ -173,4 +187,3 @@ class FullPageScreenshot extends Gatherer {
}

module.exports = FullPageScreenshot;
module.exports.MAX_SCREENSHOT_HEIGHT = MAX_SCREENSHOT_HEIGHT;
21 changes: 21 additions & 0 deletions lighthouse-core/lib/page-functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,26 @@ function getOuterHTMLSnippet(element, ignoreAttrs = [], snippetCharacterLimit =
}
}

/**
* Get the maximum size of a texture the GPU can handle
* @see https://bugs.chromium.org/p/chromium/issues/detail?id=770769#c13
*/
/* istanbul ignore next */
function getMaxTextureSize() {
try {
let canvas = document.createElement('canvas');
let gl = canvas.getContext('webgl');
const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
canvas = gl = undefined; // Cleanup for GC
return maxTextureSize;
} catch (e) {
// If the above fails for any reason we need a fallback number;
// 4096 is the max texture size on a Pixel 2 XL, so to be conservative we'll use a low value like it.
// But we'll subtract 1 just to identify this case later on.
const MAX_TEXTURE_SIZE_FALLBACK = 4095;
return MAX_TEXTURE_SIZE_FALLBACK;
}
}

/**
* Computes a memory/CPU performance benchmark index to determine rough device class.
Expand Down Expand Up @@ -521,6 +541,7 @@ module.exports = {
getOuterHTMLSnippet: getOuterHTMLSnippet,
computeBenchmarkIndex: computeBenchmarkIndex,
computeBenchmarkIndexString: computeBenchmarkIndex.toString(),
getMaxTextureSize,
getNodeDetailsString,
getNodeDetails,
getNodePathString: getNodePath.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

const FullPageScreenshotGatherer = require('../../../gather/gatherers/full-page-screenshot.js');

// Headless's default value is (1024 * 16), but this varies by device
const maxTextureSizeMock = 1024 * 8;

/**
* @param {{contentSize: {width: number, height: number}, screenSize: {width?: number, height?: number, dpr: number}, screenshotData: string[]}}
*/
Expand All @@ -17,6 +20,8 @@ function createMockDriver({contentSize, screenSize, screenshotData}) {
evaluate: async function(fn) {
if (fn.name === 'resolveNodes') {
return {};
} if (fn.name === 'getMaxTextureSize') {
return maxTextureSizeMock;
} else if (fn.name === 'getObservedDeviceMetrics') {
return {
width: screenSize.width,
Expand Down Expand Up @@ -192,7 +197,7 @@ describe('FullPageScreenshot gatherer', () => {
'Emulation.setDeviceMetricsOverride',
expect.objectContaining({
deviceScaleFactor: 1,
height: FullPageScreenshotGatherer.MAX_SCREENSHOT_HEIGHT,
height: maxTextureSizeMock,
})
);
});
Expand Down

0 comments on commit 3a820a3

Please sign in to comment.