image-upscaling.html (5914B)
1 <!DOCTYPE HTML> 2 <meta charset=utf-8> 3 <title>Largest Contentful Paint: Largest image is reported.</title> 4 <body> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/resources/testdriver.js"></script> 8 <script src="/resources/testdriver-vendor.js"></script> 9 <script src="resources/largest-contentful-paint-helpers.js"></script> 10 <script src="/common/utils.js"></script> 11 <script> 12 setup({"hide_test_state": true}); 13 assert_implements(window.LargestContentfulPaint, "LargestContentfulPaint not implemented"); 14 const imageURL = `${window.location.origin}/images/blue.png`; 15 16 async function load_image_and_get_lcp_size(t, imageStyle = {}, containerStyle = {}) { 17 let popup; 18 await test_driver.bless('Open a popup', () => { 19 popup = window.open('about:blank'); 20 t.add_cleanup(() => popup.close()); 21 }); 22 23 // Ensure the popup document is ready before manipulating it. 24 // Per spec, about:blank should load synchronously and should be 25 // immediately ready. In older Gecko versions this may not be the case, 26 // so we wait for pageshow if needed. 27 if (popup.document.readyState !== 'complete') { 28 await new Promise((resolve) => 29 popup.addEventListener('pageshow', resolve, { once: true }) 30 ); 31 } 32 33 const image = popup.document.createElement('img'); 34 image.src = imageURL; 35 36 // We decode the image to get the natural size (though it's a constant) 37 await image.decode(); 38 const naturalSize = image.width * image.height; 39 const container = popup.document.createElement('div'); 40 container.appendChild(image); 41 42 const applyStyle = (el, style = {}) => 43 Object.entries(style).forEach(([k, v]) => el.style.setProperty(k, v)); 44 applyStyle(image, imageStyle); 45 applyStyle(container, containerStyle); 46 image.id = token(); 47 container.id = token(); 48 49 const entryReported = new Promise(resolve => 50 new popup.PerformanceObserver(entryList => { 51 entryList.getEntries().forEach(entry => { 52 if (entry.id === image.id || entry.id === container.id) { 53 resolve(entry.size); 54 } 55 }); 56 }).observe({ type: 'largest-contentful-paint', buffered: true }) 57 ); 58 59 popup.document.body.appendChild(container); 60 61 return { 62 lcpSize: await entryReported, 63 naturalSize 64 }; 65 } 66 67 /* We set the image to display: none when testing background, 68 so that only the background is reported 69 and not the image itself */ 70 const load_background_image_and_get_lcp_size = (t, style) => 71 load_image_and_get_lcp_size(t, { display: 'none' }, { 72 position: 'absolute', 73 'background-image': `url(${imageURL})`, 74 ...style, 75 }); 76 77 promise_test(async t => { 78 const { naturalSize, lcpSize } = await load_image_and_get_lcp_size(t); 79 assert_equals(lcpSize, naturalSize); 80 }, 'Non-scaled image should report the natural size'); 81 82 promise_test(async t => { 83 const { naturalSize, lcpSize } = await load_image_and_get_lcp_size(t, 84 { width: '50px', height: '50px' }); 85 assert_equals(lcpSize, 50 * 50); 86 }, 'A downscaled image (width/height) should report the displayed size'); 87 88 promise_test(async t => { 89 const { naturalSize, lcpSize } = await load_image_and_get_lcp_size(t, 90 { transform: 'scale(0.5)' }); 91 assert_approx_equals(Math.floor(lcpSize), Math.floor(naturalSize / 4), 2); 92 }, 'A downscaled image (using scale) should report the displayed size'); 93 94 promise_test(async t => { 95 const { naturalSize, lcpSize } = await load_image_and_get_lcp_size(t, 96 { width: '500px', height: '500px' }); 97 assert_equals(lcpSize, naturalSize); 98 }, 'An upscaled image (width/height) should report the natural size'); 99 100 /* TODO(crbug.com/1484431): 101 Need to dig deeper into this test, to verify the implementation of scale() 102 Currently unable to upscale image*/ 103 promise_test(async t => { 104 const { naturalSize, lcpSize } = await load_image_and_get_lcp_size(t, 105 { transform: 'scale(1.0)' }); 106 assert_equals(Math.floor(lcpSize), Math.floor(naturalSize)); 107 }, 'An upscaled image (using scale) should report the natural size'); 108 109 promise_test(async t => { 110 const { naturalSize, lcpSize } = await load_image_and_get_lcp_size(t, 111 { 'object-size': '300px 300px' }); 112 assert_equals(Math.floor(lcpSize), Math.floor(naturalSize)); 113 }, 'An upscaled image (using object-size) should report the natural size'); 114 115 promise_test(async t => { 116 const { naturalSize, lcpSize } = await load_image_and_get_lcp_size(t, 117 { 'object-position': '-100px 0' }); 118 assert_equals(lcpSize, 3498); 119 }, 'Intersecting element with partial-intersecting image to report image intersection'); 120 121 promise_test(async t => { 122 const { naturalSize, lcpSize } = await load_background_image_and_get_lcp_size(t, 123 { width: '50px', height: '50px' }); 124 assert_equals(lcpSize, 50 * 50); 125 }, 'A background image larger than the container should report the container size'); 126 127 promise_test(async t => { 128 const { naturalSize, lcpSize } = await load_background_image_and_get_lcp_size(t, 129 { width: '300px', height: '300px' }); 130 assert_equals(lcpSize, naturalSize); 131 }, 'A background image smaller than the container should report the natural size'); 132 133 promise_test(async t => { 134 const { naturalSize, lcpSize } = await load_background_image_and_get_lcp_size(t, 135 { 136 width: '300px', 137 height: '300px', 138 'background-size': '10px 10px', 139 'background-repeat': 'no-repeat' 140 }); 141 assert_equals(lcpSize, 100); 142 }, 'A scaled-down background image should report the background size'); 143 </script> 144 </body>