Skip to content

Commit

Permalink
LCP: Test different scenarios of image upscaling
Browse files Browse the repository at this point in the history
  • Loading branch information
noamr committed May 4, 2022
1 parent 19666e5 commit bf3b78c
Showing 1 changed file with 98 additions and 0 deletions.
98 changes: 98 additions & 0 deletions largest-contentful-paint/image-upscaling.html
@@ -0,0 +1,98 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Largest Contentful Paint: largest image is reported.</title>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/largest-contentful-paint-helpers.js"></script>
<script src="/common/utils.js"></script>
<script>
setup(() =>
assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint is not implemented"));

const imageURL = `${window.location.origin}/images/blue.png`;
async function load_image_and_get_lcp_size(t, imageStyle = {}, containerStyle = {}) {
const popup = window.open('about:blank');
t.add_cleanup(() => popup.close());
const image = popup.document.createElement('img');
image.src = imageURL;
await image.decode();
const naturalSize = image.width * image.height;
const container = popup.document.createElement('div');
container.appendChild(image);
const applyStyle = (el, style = {}) =>
Object.entries(style).forEach(([k, v]) => el.style.setProperty(k, v));

applyStyle(image, imageStyle);
applyStyle(container, containerStyle);
image.id = token();
const entryReported = new Promise(resolve => new popup.PerformanceObserver(entryList => {
entryList.getEntries().forEach(entry => {
if (entry.id === image.id)

This comment has been minimized.

Copy link
@sefeng211

sefeng211 Jun 16, 2022

Contributor

This check doesn't work for load_background_image_and_get_lcp_size right? As the image container is not the img, but div, and the id of the `div is "".

This comment has been minimized.

Copy link
@sefeng211

sefeng211 Jun 16, 2022

Contributor

I can fix it on the Gecko side if you think my understanding is correct. @noamr

resolve(entry.size);
});
}).observe({type: 'largest-contentful-paint'}));
popup.document.body.appendChild(container);
const timeout = new Promise(resolve => t.step_timeout(() => resolve('not reported'), 1000));
return {lcpSize: (await Promise.any([entryReported, timeout])), naturalSize};
}

const load_background_image_and_get_lcp_size = (t, style) =>
load_image_and_get_lcp_size(t, {display: 'none'},
{
position: 'absolute',
'background-image': `url(${imageURL})`,
...style,
});

promise_test(async t => {
const {naturalSize, lcpSize} = await load_image_and_get_lcp_size(t);
assert_equals(lcpSize, naturalSize);
}, 'Non-scaled image should report the natural size');

promise_test(async t => {
const {naturalSize, lcpSize} = await load_image_and_get_lcp_size(t, {width: '50px', height: '50px'});
assert_equals(lcpSize, 50 * 50);
}, 'A downscaled image (width/height) should report the displayed size');

promise_test(async t => {
const {naturalSize, lcpSize} = await load_image_and_get_lcp_size(t, {transform: 'scale(0.5)'});
assert_equals(Math.floor(lcpSize), Math.floor(naturalSize / 4));
}, 'A downscaled image (using scale) should report the displayed size');

promise_test(async t => {
const {naturalSize, lcpSize} = await load_image_and_get_lcp_size(t, {width: '500px', height: '500px'});
assert_equals(lcpSize, naturalSize);
}, 'An upscaled image (width/height) should report the natural size');

promise_test(async t => {
const {naturalSize, lcpSize} = await load_image_and_get_lcp_size(t, {transform: 'scale(2)'});
assert_equals(Math.floor(lcpSize), Math.floor(naturalSize));
}, 'An upscaled image (using scale) should report the natural size');

This comment has been minimized.

Copy link
@sefeng211

sefeng211 Jun 16, 2022

Contributor

@noamr I am trying to understand the computation flow for this particular test, the scale one.

I used w3c/largest-contentful-paint#99 as a reference, here's what I see.

  1. The intersectingClientContentRect should be the scaled rectangle because it uses clientContentRect which has transform applied. So the size is the scaled size.

  2. and the scaleFactor is going to be 1 because concreteDimensions doesn't have transform applied, so concreteArea == naturalArea.

  3. Hence the reported size is going to be the scaled size, not natural size.

What am I missing? Thanks

This comment has been minimized.

Copy link
@noamr

noamr Jun 16, 2022

Author Contributor

You're right, there's a mistake in the LCP PR. I'll double-check and revise.

This comment has been minimized.

Copy link
@noamr

noamr Jun 16, 2022

Author Contributor

@sefeng211 I believe the algorithm is now fixed.

The idea is to:

  • Find the scale of the image (area of bounding client rect of the actual image / area of image natural dimensions)
  • Find the viewport intersection of the actual image
  • Divide viewport intersection size with scale

This comment has been minimized.

Copy link
@sefeng211

sefeng211 Jun 16, 2022

Contributor

Yeah, looks good now.

Thanks for fixing it!


promise_test(async t => {
const {naturalSize, lcpSize} = await load_image_and_get_lcp_size(t, {'object-size': '300px 300px'});
assert_equals(Math.floor(lcpSize), Math.floor(naturalSize));
}, 'An upscaled image (using object-size) should report the natural size');

promise_test(async t => {
const {naturalSize, lcpSize} = await load_image_and_get_lcp_size(t, {'object-position': '-100px 0'});
assert_equals(lcpSize, 3498);
}, 'An intersecting element with a partial-intersecting image (object-position) should report the image intersection');

promise_test(async t => {
const {naturalSize, lcpSize} = await load_background_image_and_get_lcp_size(t, {width: '50px', height: '50px'});
assert_equals(lcpSize, 50 * 50);
}, 'A background image larger than the container should report the container size');

promise_test(async t => {
const {naturalSize, lcpSize} = await load_background_image_and_get_lcp_size(t, {width: '300px', height: '300px'});
assert_equals(lcpSize, naturalSize);
}, 'A background image smaller than the container should report the natural size');

promise_test(async t => {
const {naturalSize, lcpSize} = await load_background_image_and_get_lcp_size(t, {width: '300px', height: '300px', 'background-size': '10px 10x'});
assert_equals(lcpSize, 100);
}, 'A scaled-down background image should report the background size');
</script>
</body>

0 comments on commit bf3b78c

Please sign in to comment.