picture-aspect-ratio.html (9255B)
1 <!doctype html> 2 <title>Image width and height attributes are used to infer aspect-ratio</title> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <style> 6 img:not([nowidth]) { 7 width: 100%; 8 max-width: 100px; 9 height: auto; 10 } 11 </style> 12 <picture> 13 <source srcset="/images/green-100x50.png"></source> 14 <img> 15 </picture> 16 17 <picture> 18 <source srcset="/images/green-100x50.png" width="100" height="100"></source> 19 <img> 20 </picture> 21 22 <picture> 23 <source srcset="/images/green-100x50.png" width="100" height="100"></source> 24 <img width="50" height="100"> 25 </picture> 26 27 <picture> 28 <source srcset="/images/green-100x50.png" width="100" height="100" id="twosource-s1"></source> 29 <source srcset="/images/green-100x50.png" width="300" height="150"></source> 30 <img id="twosource-img"> 31 </picture> 32 33 <div style="width: 100px;"> 34 <picture> 35 <source srcset="/images/green-100x50.png" width="100%" height="50%" id="percent-src"></source> 36 <img style="contain:size;" id="percent-img" nowidth="true"> 37 </picture> 38 </div> 39 40 <picture> 41 <source srcset="/images/green-100x50.png" width="100abc" height="50abc" id="trailing-src"></source> 42 <img style="contain:size;" id="trailing-img" nowidth="true"> 43 </picture> 44 45 <script> 46 let guard = async_test("source width and height attributes are used to infer aspect-ratio in <picture>"); 47 function assert_ratio(img, expected, description) { 48 let epsilon = 0.001; 49 assert_approx_equals(parseFloat(getComputedStyle(img).width, 10) / parseFloat(getComputedStyle(img).height, 10), 50 expected, epsilon, description); 51 } 52 53 function createPicture(width, height) { 54 var picture = document.createElement("picture"); 55 var source = document.createElement("source"); 56 if (width !== undefined) 57 source.setAttribute("width", width); 58 if (height !== undefined) 59 source.setAttribute("height", height); 60 source.setAttribute("srcset", "/images/green.png"); 61 picture.appendChild(source); 62 var img = document.createElement("img"); 63 picture.appendChild(img); 64 document.body.appendChild(picture); 65 return img; 66 } 67 68 function assert_cs(img, val) { 69 assert_equals(getComputedStyle(img).aspectRatio, val); 70 } 71 72 // Create and append a new image and immediately check the ratio. 73 // This is not racy because the spec requires the user agent to queue a task: 74 // https://html.spec.whatwg.org/multipage/images.html#updating-the-image-data 75 test(function() { 76 var img = createPicture(100, 100); 77 assert_ratio(img, 1.0); 78 assert_cs(img, "auto 100 / 100"); 79 img.style.display = "none"; 80 img.setAttribute("nowidth", "true"); 81 assert_equals(getComputedStyle(img).width, "100px"); 82 assert_equals(getComputedStyle(img).height, "100px"); 83 var source = img.previousSibling; 84 assert_equals(getComputedStyle(source).width, "auto"); 85 assert_equals(getComputedStyle(source).height, "auto"); 86 }, "Computed style for width/height/aspect-ratio"); 87 88 test(function() { 89 img = createPicture(200, 100); 90 img.setAttribute("width", 250); 91 img.setAttribute("height", 50); 92 assert_ratio(img, 2.0); 93 assert_cs(img, "auto 200 / 100"); 94 img.style.display = "none"; 95 img.setAttribute("nowidth", "true"); 96 assert_equals(getComputedStyle(img).width, "200px"); 97 assert_equals(getComputedStyle(img).height, "100px"); 98 source = img.previousSibling; 99 assert_equals(getComputedStyle(source).width, "auto"); 100 assert_equals(getComputedStyle(source).height, "auto"); 101 }, "Source width/height should take precedence over img attributes."); 102 103 test(function() { 104 img.parentNode.removeChild(img.previousSibling); 105 assert_cs(img, "auto 250 / 50"); 106 img.src = "/images/green.png"; 107 assert_ratio(img, 5.0); 108 img.style.display = "none"; 109 img.setAttribute("nowidth", "true"); 110 assert_equals(getComputedStyle(img).width, "250px"); 111 assert_equals(getComputedStyle(img).height, "50px"); 112 }, "Make sure style gets invalidated correctly when the source gets removed."); 113 114 test(function() { 115 img = createPicture(100, undefined); 116 img.setAttribute("width", 200); 117 img.setAttribute("height", 100); 118 assert_cs(img, "auto"); 119 img.style.display = "none"; 120 img.setAttribute("nowidth", "true"); 121 assert_equals(getComputedStyle(img).width, "100px"); 122 assert_equals(getComputedStyle(img).height, "auto"); 123 }, "If the <source> has only one of width/height, we don't get an aspect ratio, even if the <img> has both."); 124 125 test(function() { 126 img = createPicture(undefined, undefined); 127 img.setAttribute("width", 200); 128 img.setAttribute("height", 100); 129 assert_cs(img, "auto 200 / 100"); 130 }, "If we don't have width/height on the source, we fall back to width/height on the <img>."); 131 132 test(function() { 133 img = createPicture(100, undefined); 134 img.parentNode.style.display = "none"; 135 img.setAttribute("width", "200"); 136 img.setAttribute("height", "300"); 137 img.setAttribute("nowidth", "true"); 138 assert_cs(img, "auto"); 139 assert_equals(getComputedStyle(img).width, "100px"); 140 assert_equals(getComputedStyle(img).height, "auto"); 141 }, "If we only have one width attribute, we should get width mapped but no aspect ratio, even if <img> has attributes."); 142 143 test(function() { 144 img = createPicture(undefined, 100); 145 img.parentNode.style.display = "none"; 146 img.setAttribute("width", "200"); 147 img.setAttribute("height", "300"); 148 img.setAttribute("nowidth", "true"); 149 assert_cs(img, "auto"); 150 assert_equals(getComputedStyle(img).width, "auto"); 151 assert_equals(getComputedStyle(img).height, "100px"); 152 }, "If we only have height attribute, we should get height mapped but no aspect ratio, even if <img> has attributes."); 153 154 test(function() { 155 img = createPicture(100, 100); 156 assert_cs(img, "auto 100 / 100"); 157 img.previousSibling.setAttribute("height", "300"); 158 assert_cs(img, "auto 100 / 300"); 159 img.previousSibling.setAttribute("width", "10"); 160 assert_cs(img, "auto 10 / 300"); 161 img.style.display = "none"; 162 img.setAttribute("nowidth", "true"); 163 assert_equals(getComputedStyle(img).width, "10px"); 164 assert_equals(getComputedStyle(img).height, "300px"); 165 }, "Dynamically changing width/height should change computed style"); 166 167 test(function() { 168 img = document.getElementById("twosource-img"); 169 assert_cs(img, "auto 100 / 100"); 170 source = document.getElementById("twosource-s1"); 171 source.setAttribute("type", "x-foo/x-bar"); 172 // We should now match the second source 173 assert_cs(img, "auto 300 / 150"); 174 img.style.display = "none"; 175 img.setAttribute("nowidth", "true"); 176 assert_equals(getComputedStyle(img).width, "300px"); 177 assert_equals(getComputedStyle(img).height, "150px"); 178 }, "Changing which <source> matches should change computed style"); 179 180 test(function() { 181 img = document.getElementById("percent-img"); 182 assert_equals(img.offsetWidth, 100); 183 assert_equals(img.offsetHeight, 0); 184 assert_cs(img, "auto"); 185 source = document.getElementById("percent-src"); 186 assert_equals(source.width, 100); 187 assert_equals(source.height, 50); 188 img.style.display = "none"; 189 img.setAttribute("nowidth", "true"); 190 assert_equals(getComputedStyle(img).width, "100%"); 191 assert_equals(getComputedStyle(img).height, "50%"); 192 }, "Percentages on source should be ignored for aspect-ratio but used for width/height."); 193 194 test(function() { 195 img = document.getElementById("trailing-img"); 196 assert_equals(img.offsetWidth, 100); 197 assert_equals(img.offsetHeight, 50); 198 assert_cs(img, "auto 100 / 50"); 199 source = document.getElementById("trailing-src"); 200 assert_equals(source.width, 100); 201 assert_equals(source.height, 50); 202 img.style.display = "none"; 203 img.setAttribute("nowidth", "true"); 204 assert_equals(getComputedStyle(img).width, "100px"); 205 assert_equals(getComputedStyle(img).height, "50px"); 206 }, "Trailing garbage should be ignored but not make the attribute invalid"); 207 208 onload = function() { 209 let images = document.querySelectorAll("img"); 210 test(function() { 211 var img = images[0]; 212 assert_ratio(img, 2.0, "2.0 is the original aspect ratio of green-100x50.png"); 213 assert_cs(img, "auto"); 214 img.style.display = "none"; 215 img.setAttribute("nowidth", "true"); 216 assert_equals(getComputedStyle(img).width, "auto"); 217 assert_equals(getComputedStyle(img).height, "auto"); 218 }, "Loaded picture test: Both <source> and <img> are without width and height attributes"); 219 220 test(function () { 221 img = images[1]; 222 assert_ratio(img, 2.0, "Loaded image's aspect ratio, at least by default, overrides width / height ratio."); 223 assert_cs(img, "auto 100 / 100"); 224 img.style.display = "none"; 225 img.setAttribute("nowidth", "true"); 226 assert_equals(getComputedStyle(img).width, "100px"); 227 assert_equals(getComputedStyle(img).height, "100px"); 228 }, "Loaded picture test: <source> with width and height attributes, <img> without width and height attributes"); 229 230 test(function () { 231 img = images[2]; 232 assert_ratio(img, 2.0, "Loaded image's aspect ratio, at least by default, overrides width / height ratio (2)."); 233 assert_cs(img, "auto 100 / 100"); 234 img.style.display = "none"; 235 img.setAttribute("nowidth", "true"); 236 assert_equals(getComputedStyle(img).width, "100px"); 237 assert_equals(getComputedStyle(img).height, "100px"); 238 }, "Loaded picture test: Both <source> and <img> are with width and height attributes"); 239 240 guard.done(); 241 }; 242 </script>