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

core(full-page-screenshot): revise logic for determining dimensions #14920

Merged
merged 19 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
12 changes: 12 additions & 0 deletions cli/test/fixtures/scaled-overflow-content.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=0.5">
<title>Document</title>
</head>
<body style="overflow: scroll;">
<h1>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</h1>
</body>
</html>
2 changes: 2 additions & 0 deletions cli/test/smokehouse/core-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import formsAutoComplete from './test-definitions/forms-autocomplete.js';
import fpsMax from './test-definitions/fps-max.js';
import fpsMaxPassive from './test-definitions/fps-max-passive.js';
import fpsScaled from './test-definitions/fps-scaled.js';
import fpsOverflowX from './test-definitions/fps-overflow-x.js';
import issuesMixedContent from './test-definitions/issues-mixed-content.js';
import lanternFetch from './test-definitions/lantern-fetch.js';
import lanternIdleCallbackLong from './test-definitions/lantern-idle-callback-long.js';
Expand Down Expand Up @@ -80,6 +81,7 @@ const smokeTests = [
formsAutoComplete,
fpsMax,
fpsScaled,
fpsOverflowX,
fpsMaxPassive,
issuesMixedContent,
lanternFetch,
Expand Down
61 changes: 61 additions & 0 deletions cli/test/smokehouse/test-definitions/fps-overflow-x.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* @license Copyright 2023 The Lighthouse Authors. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

/** @type {LH.Config} */
const config = {
extends: 'lighthouse:default',
settings: {
onlyCategories: ['performance'],
},
};

/**
* @type {Smokehouse.ExpectedRunnerResult}
*/
const expectations = {
artifacts: {
ViewportDimensions: {
innerWidth: 1325,
innerHeight: 2647,
outerWidth: 412,
outerHeight: 823,
devicePixelRatio: 1.75,
},
},
lhr: {
requestedUrl: 'http://localhost:10200/scaled-overflow-content.html',
finalDisplayedUrl: 'http://localhost:10200/scaled-overflow-content.html',
audits: {},
fullPageScreenshot: {
nodes: {
_includes: [
[
/-BODY$/,
{
top: 21,
bottom: 58,
left: 8,
right: 816,
width: 808,
height: 37,
},
],
],
},
screenshot: {
height: 1324,
width: 412,
},
},
},
};

export default {
id: 'fps-overflow-x',
expectations,
config,
};

4 changes: 2 additions & 2 deletions cli/test/smokehouse/test-definitions/fps-scaled.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ const expectations = {
],
},
screenshot: {
height: 2000,
width: 824,
adamraine marked this conversation as resolved.
Show resolved Hide resolved
height: 1000,
width: 412,
},
},
},
Expand Down
39 changes: 12 additions & 27 deletions core/gather/gatherers/full-page-screenshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,6 @@ function getObservedDeviceMetrics() {
};
}

/**
* The screenshot dimensions are sized to `window.outerHeight` / `window.outerWidth`,
* however the bounding boxes of the elements are relative to `window.innerHeight` / `window.innerWidth`.
*/
function getScreenshotAreaSize() {
return {
width: window.innerWidth,
height: window.innerHeight,
};
}

function waitForDoubleRaf() {
return new Promise((resolve) => {
requestAnimationFrame(() => requestAnimationFrame(resolve));
Expand All @@ -79,13 +68,13 @@ class FullPageScreenshot extends FRGatherer {
const session = context.driver.defaultSession;
const metrics = await session.sendCommand('Page.getLayoutMetrics');

// Height should be as tall as the content.
// Scale the emulated height to reach the content height.
const fullHeight = Math.round(
deviceMetrics.height *
metrics.cssContentSize.height /
metrics.cssLayoutViewport.clientHeight
);
// To obtain a full page screenshot, we resize the emulated viewport height to
// the maximum between visual-viewport height and the scaled document height.
// Final height is capped to the maximum size allowance of WebP format.
// Height needs to be rounded to an integer for Emulation.setDeviceMetricOverrides.
const fullHeight = Math.round(Math.max(
deviceMetrics.height, metrics.cssContentSize.height * metrics.cssVisualViewport.scale
adamraine marked this conversation as resolved.
Show resolved Hide resolved
));
const height = Math.min(fullHeight, MAX_WEBP_SIZE);

// Setup network monitor before we change the viewport.
Expand Down Expand Up @@ -128,18 +117,14 @@ class FullPageScreenshot extends FRGatherer {
format: 'webp',
quality: FULL_PAGE_SCREENSHOT_QUALITY,
});
const metrics = await context.driver.defaultSession.sendCommand('Page.getLayoutMetrics');
const data = 'data:image/webp;base64,' + result.data;

const screenshotAreaSize =
await context.driver.executionContext.evaluate(getScreenshotAreaSize, {
args: [],
useIsolation: true,
});

return {
data,
width: screenshotAreaSize.width,
height: screenshotAreaSize.height,
// Since we resized emulated viewport to match the desired screenshot size,
// it is safe to rely on scaled visual viewport css dimensions.
width: Math.round(metrics.cssVisualViewport.clientWidth * metrics.cssVisualViewport.scale),
height: Math.round(metrics.cssVisualViewport.clientHeight * metrics.cssVisualViewport.scale),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why isn't this set to the above height variable, the one given the setDeviceMetricsOverride?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, it should be exactly the same I guess. Seems good.

};
}

Expand Down
15 changes: 2 additions & 13 deletions core/test/gather/gatherers/full-page-screenshot-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,22 @@ import FullPageScreenshotGatherer from '../../../gather/gatherers/full-page-scre
let contentSize;
/** @type {{width?: number, height?: number, dpr: number}} */
let screenSize;
/** @type {{width?: number, height?: number}} */
let screenshotAreaSize;
/** @type {string[]} */
let screenshotData;
let mockContext = createMockContext();

beforeEach(() => {
contentSize = {width: 100, height: 100};
screenSize = {width: 100, height: 100, dpr: 1};
screenshotAreaSize = contentSize;
screenshotData = [];
mockContext = createMockContext();
mockContext.driver.defaultSession.sendCommand.mockImplementation((method) => {
if (method === 'Page.getLayoutMetrics') {
return {
cssContentSize: contentSize,
// See comment within _takeScreenshot() implementation
cssLayoutViewport: {clientWidth: screenSize.width, clientHeight: screenSize.height},
cssVisualViewport: {clientWidth: contentSize.width, clientHeight: contentSize.height,
scale: 1.0},
};
}
if (method === 'Page.captureScreenshot') {
Expand All @@ -50,11 +48,6 @@ beforeEach(() => {
},
deviceScaleFactor: screenSize.dpr,
};
} else if (fn.name === 'getScreenshotAreaSize') {
return {
width: screenshotAreaSize.width,
height: screenshotAreaSize.height,
};
} else if (fn.name === 'waitForDoubleRaf') {
return {};
} else {
Expand All @@ -68,7 +61,6 @@ describe('FullPageScreenshot gatherer', () => {
const fpsGatherer = new FullPageScreenshotGatherer();
contentSize = {width: 412, height: 2000};
screenSize = {width: 412, height: 412};
screenshotAreaSize = contentSize;

mockContext.settings = {
...mockContext.settings,
Expand Down Expand Up @@ -97,7 +89,6 @@ describe('FullPageScreenshot gatherer', () => {
const fpsGatherer = new FullPageScreenshotGatherer();
contentSize = {width: 412, height: 2000};
screenSize = {width: 412, height: 412};
screenshotAreaSize = contentSize;

mockContext.settings = {
...mockContext.settings,
Expand Down Expand Up @@ -131,7 +122,6 @@ describe('FullPageScreenshot gatherer', () => {
const fpsGatherer = new FullPageScreenshotGatherer();
contentSize = {width: 500, height: 1500};
screenSize = {width: 500, height: 500, dpr: 2};
screenshotAreaSize = contentSize;
mockContext.settings = {
...mockContext.settings,
screenEmulation: {
Expand Down Expand Up @@ -178,7 +168,6 @@ describe('FullPageScreenshot gatherer', () => {

contentSize = {width: 412, height: 100000};
screenSize = {width: 412, height: 412, dpr: 1};
screenshotAreaSize = contentSize;
mockContext.settings = {
...mockContext.settings,
formFactor: 'mobile',
Expand Down