| <!doctype html> |
| <title>Image width and height attributes are used to infer aspect-ratio</title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <style> |
| img:not([nowidth]) { |
| width: 100%; |
| max-width: 100px; |
| height: auto; |
| } |
| </style> |
| <picture> |
| <source srcset="/images/green-100x50.png"></source> |
| <img> |
| </picture> |
| |
| <picture> |
| <source srcset="/images/green-100x50.png" width="100" height="100"></source> |
| <img> |
| </picture> |
| |
| <picture> |
| <source srcset="/images/green-100x50.png" width="100" height="100"></source> |
| <img width="50" height="100"> |
| </picture> |
| |
| <picture> |
| <source srcset="/images/green-100x50.png" width="100" height="100" id="twosource-s1"></source> |
| <source srcset="/images/green-100x50.png" width="300" height="150"></source> |
| <img id="twosource-img"> |
| </picture> |
| |
| <div style="width: 100px;"> |
| <picture> |
| <source srcset="/images/green-100x50.png" width="100%" height="50%" id="percent-src"></source> |
| <img style="contain:size;" id="percent-img" nowidth="true"> |
| </picture> |
| </div> |
| |
| <picture> |
| <source srcset="/images/green-100x50.png" width="100abc" height="50abc" id="trailing-src"></source> |
| <img style="contain:size;" id="trailing-img" nowidth="true"> |
| </picture> |
| |
| <script> |
| let t = async_test("source width and height attributes are used to infer aspect-ratio in <picture>"); |
| function assert_ratio(img, expected, description) { |
| let epsilon = 0.001; |
| assert_approx_equals(parseFloat(getComputedStyle(img).width, 10) / parseFloat(getComputedStyle(img).height, 10), |
| expected, epsilon, description); |
| } |
| |
| function createPicture(width, height) { |
| var picture = document.createElement("picture"); |
| var source = document.createElement("source"); |
| if (width !== undefined) |
| source.setAttribute("width", width); |
| if (height !== undefined) |
| source.setAttribute("height", height); |
| source.setAttribute("srcset", "/images/green.png"); |
| picture.appendChild(source); |
| var img = document.createElement("img"); |
| picture.appendChild(img); |
| document.body.appendChild(picture); |
| return img; |
| } |
| |
| function assert_cs(img, val) { |
| assert_equals(getComputedStyle(img).aspectRatio, val); |
| } |
| |
| // Create and append a new image and immediately check the ratio. |
| // This is not racy because the spec requires the user agent to queue a task: |
| // https://html.spec.whatwg.org/multipage/images.html#updating-the-image-data |
| test(function() { |
| var img = createPicture(100, 100); |
| assert_ratio(img, 1.0); |
| assert_cs(img, "auto 100 / 100"); |
| img.style.display = "none"; |
| img.setAttribute("nowidth", "true"); |
| assert_equals(getComputedStyle(img).width, "100px"); |
| assert_equals(getComputedStyle(img).height, "100px"); |
| var source = img.previousSibling; |
| assert_equals(getComputedStyle(source).width, "auto"); |
| assert_equals(getComputedStyle(source).height, "auto"); |
| |
| // Source width/height should take precedence over img attributes. |
| img = createPicture(200, 100); |
| img.setAttribute("width", 250); |
| img.setAttribute("height", 50); |
| assert_ratio(img, 2.0); |
| assert_cs(img, "auto 200 / 100"); |
| img.style.display = "none"; |
| img.setAttribute("nowidth", "true"); |
| assert_equals(getComputedStyle(img).width, "200px"); |
| assert_equals(getComputedStyle(img).height, "100px"); |
| source = img.previousSibling; |
| assert_equals(getComputedStyle(source).width, "auto"); |
| assert_equals(getComputedStyle(source).height, "auto"); |
| |
| // Make sure style gets invalidated correctly when the source gets removed. |
| img.parentNode.removeChild(img.previousSibling); |
| assert_cs(img, "auto 250 / 50"); |
| img.src = "/images/green.png"; |
| assert_ratio(img, 5.0); |
| img.style.display = "none"; |
| img.setAttribute("nowidth", "true"); |
| assert_equals(getComputedStyle(img).width, "250px"); |
| assert_equals(getComputedStyle(img).height, "50px"); |
| |
| // If the <source> has only one of width/height, we don't get an aspect |
| // ratio, even if the <img> has both. |
| img = createPicture(100, undefined); |
| img.setAttribute("width", 200); |
| img.setAttribute("height", 100); |
| assert_cs(img, "auto"); |
| img.style.display = "none"; |
| img.setAttribute("nowidth", "true"); |
| assert_equals(getComputedStyle(img).width, "100px"); |
| assert_equals(getComputedStyle(img).height, "auto"); |
| |
| // If we don't have width/height on the source, we fall back to width/height |
| // on the <img>. |
| img = createPicture(undefined, undefined); |
| img.setAttribute("width", 200); |
| img.setAttribute("height", 100); |
| assert_cs(img, "auto 200 / 100"); |
| |
| // If we only have one width/height attribute, we should get that attribute |
| // mapped but no aspect ratio, even if <img> has attributes. |
| img = createPicture(100, undefined); |
| img.parentNode.style.display = "none"; |
| img.setAttribute("width", "200"); |
| img.setAttribute("height", "300"); |
| img.setAttribute("nowidth", "true"); |
| assert_cs(img, "auto"); |
| assert_equals(getComputedStyle(img).width, "100px"); |
| assert_equals(getComputedStyle(img).height, "auto"); |
| |
| img = createPicture(undefined, 100); |
| img.parentNode.style.display = "none"; |
| img.setAttribute("width", "200"); |
| img.setAttribute("height", "300"); |
| img.setAttribute("nowidth", "true"); |
| assert_cs(img, "auto"); |
| assert_equals(getComputedStyle(img).width, "auto"); |
| assert_equals(getComputedStyle(img).height, "100px"); |
| |
| // Testing dynamic changes |
| img = createPicture(100, 100); |
| assert_cs(img, "auto 100 / 100"); |
| img.previousSibling.setAttribute("height", "300"); |
| assert_cs(img, "auto 100 / 300"); |
| img.previousSibling.setAttribute("width", "10"); |
| assert_cs(img, "auto 10 / 300"); |
| img.style.display = "none"; |
| img.setAttribute("nowidth", "true"); |
| assert_equals(getComputedStyle(img).width, "10px"); |
| assert_equals(getComputedStyle(img).height, "300px"); |
| |
| img = document.getElementById("twosource-img"); |
| assert_cs(img, "auto 100 / 100"); |
| source = document.getElementById("twosource-s1"); |
| source.setAttribute("type", "x-foo/x-bar"); |
| // We should now match the second source |
| assert_cs(img, "auto 300 / 150"); |
| img.style.display = "none"; |
| img.setAttribute("nowidth", "true"); |
| assert_equals(getComputedStyle(img).width, "300px"); |
| assert_equals(getComputedStyle(img).height, "150px"); |
| |
| // Percentages on source should be ignored for aspect-ratio but used for |
| // width/height. |
| img = document.getElementById("percent-img"); |
| assert_equals(img.offsetWidth, 100); |
| assert_equals(img.offsetHeight, 0); |
| assert_cs(img, "auto"); |
| source = document.getElementById("percent-src"); |
| assert_equals(source.width, 100); |
| assert_equals(source.height, 50); |
| img.style.display = "none"; |
| img.setAttribute("nowidth", "true"); |
| assert_equals(getComputedStyle(img).width, "100%"); |
| assert_equals(getComputedStyle(img).height, "50%"); |
| |
| // Trailing garbage should be ignored but not invalidate anything. |
| img = document.getElementById("trailing-img"); |
| assert_equals(img.offsetWidth, 100); |
| assert_equals(img.offsetHeight, 50); |
| assert_cs(img, "auto 100 / 50"); |
| source = document.getElementById("trailing-src"); |
| assert_equals(source.width, 100); |
| assert_equals(source.height, 50); |
| img.style.display = "none"; |
| img.setAttribute("nowidth", "true"); |
| assert_equals(getComputedStyle(img).width, "100px"); |
| assert_equals(getComputedStyle(img).height, "50px"); |
| }, "Computed style"); |
| |
| onload = t.step_func_done(function() { |
| let images = document.querySelectorAll("img"); |
| assert_ratio(images[0], 2.0, "2.0 is the original aspect ratio of green-100x50.png"); |
| assert_ratio(images[1], 2.0, "Loaded image's aspect ratio, at least by default, overrides width / height ratio."); |
| assert_ratio(images[2], 2.0, "Loaded image's aspect ratio, at least by default, overrides width / height ratio (2)."); |
| }); |
| </script> |