Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test has a WPT meta file that expects 58 subtest issues.
- This WPT test may be referenced by the following Test IDs:
- /html/semantics/embedded-content/the-img-element/naturalWidth-naturalHeight-width-height.html - WPT Dashboard Interop Dashboard
<!doctype html>
<head>
<meta charset="utf-8">
<title>HTMLImageElement attributes naturalWidth, naturalHeight, width, height</title>
<link rel="help" href="https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-naturalwidth-dev">
<link rel="help" href="https://html.spec.whatwg.org/multipage/images.html#density-corrected-intrinsic-width-and-height">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
#scroller {
/* We wrap all the test content in a scroller so that it doesn't push
* the textual test-results too far out of view.
*/
border: 1px solid black;
height: 400px;
width: max-content;
overflow: scroll;
}
#containingBlock {
/* There are a few SVG images here that size so that their margin-box fills
* their containing block width. We define a specific size here so that we
* can then check for it (minus the margins) in the "data-width" attribute.
*/
width: 740px;
}
img {
/* This styling is just cosmetic, to help visualize the images. */
border: 5px solid teal;
margin: 5px;
display: block;
}
</style>
<!-- We specify the img elements in a <template> and then clone them for
testing, so that we can dynamically generate and test several variants
of each img. -->
<template id="imgTemplates">
<!-- For each img element:
* The "data-natural-{width,height}" attributes represent the expected
values of the img element's "naturalWidth" and "naturalHeight" IDL
attributes. This test implicitly expects the "width" and "height" IDL
attributes to have those same expected values; but in cases where that's
not correct, we provide the actual expected value in the
"data-{width,height}" attributes (as distinguished from
data-natural-{width,height}).
* The "data-density" attribute indicates which natural dimensions are
SVG-intrinsic (and thus should be density-corrected): "both" (default for
raster), "width", "height", or "none". Default dimensions (300x150) and
dimensions derived from fitting an aspect ratio into the default object
size are not density-corrected.
* The "title" attribute is a description of the scenario being tested, and
it must be unique to satisfy the test harness requirements. -->
<!-- JPG images -->
<img src="resources/cat.jpg"
title="raster image"
data-natural-width="320" data-natural-height="240">
<img src="resources/cat.jpg" width="10" height="10"
title="raster image with width/height attributes"
data-natural-width="320" data-natural-height="240"
data-width="10" data-height="10"
data-not-rendered-width="10" data-not-rendered-height="10">
<!-- Use "size-comes-from-broken-image-icon" attribute to opt out of checking
img.width and img.height, because they come from the UA-dependent
size of the broken image icon: -->
<img src="non-existent.jpg"
title="non existent image, no natural dimensions"
data-natural-width="0" data-natural-height="0"
size-comes-from-broken-image-icon>
<img src="non-existent.jpg" width="10" height="10"
title="non existent image with width/height attributes, no natural dimensions"
data-natural-width="0" data-natural-height="0"
data-width="10" data-height="10"
data-not-rendered-width="10" data-not-rendered-height="10">
<!-- First group of SVG images: no viewBox, with a missing (or edge-casey, i.e.
negative or percent-valued) value for the width and/or height attr on the
root svg element in a SVG image. -->
title="SVG image, no natural dimensions"
data-density="none"
data-natural-width="300" data-natural-height="150">
width="40" height="10"
data-width="40" data-height="10"
data-not-rendered-width="40" data-not-rendered-height="10"
title="SVG image with width/height attrs, no natural dimensions"
data-density="none"
data-natural-width="300" data-natural-height="150">
width="40"
data-width="40" data-not-rendered-width="40"
title="SVG image with width attr, no natural dimensions"
data-density="none"
data-natural-width="300" data-natural-height="150">
height="10"
data-height="10" data-not-rendered-height="10"
title="SVG image with height attr, no natural dimensions"
data-density="none"
data-natural-width="300" data-natural-height="150">
<!-- Note: percent values can't be resolved when determining natural
dimensions, so the exact percentage shouldn't matter. -->
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='400%' height='10%'></svg>"
title="SVG image, percengage natural dimensions"
data-density="none"
data-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-400%' height='-10%'></svg>"
title="SVG image, negative percengage natural dimensions"
data-density="none"
data-natural-width="300" data-natural-height="150">
<!-- If only one attribute is present, it should show up as a natural
dimension, without influencing the other natural dimension. -->
title="SVG image, with natural width"
data-density="width"
data-natural-width="60" data-natural-height="150">
title="SVG image, with natural height"
data-density="height"
data-natural-width="300" data-natural-height="60">
<!-- If either attribute is 0 or a negative length, it should show up as a
natural dimension: of 0. -->
title="SVG image, with natural width of 0"
data-density="width"
data-natural-width="0" data-natural-height="150">
title="SVG image, with natural height of 0"
data-density="height"
data-natural-width="300" data-natural-height="0">
title="SVG image, with natural width being negative"
data-density="none"
data-natural-width="300" data-natural-height="150">
title="SVG image, with natural height being negative"
data-density="none"
data-natural-width="300" data-natural-height="150">
<!-- Second group of SVG images: Same as above, but now with a viewBox that grants a
3:1 aspect-ratio; whenever we know one natural dimension, that should
combine with the aspect ratio to produce the other natural dimension.
NOTE: for a few subtests here, the image ends up expanding to fill the
containing block's width, i.e. rendering at a larger size than its natural
size. In those cases, we include 'data-width' & 'data-height' attributes,
so that this test's JS can validate that img.width and img.height return
these expected larger values. (Otherwise, we expect img.width and
img.height to return the same values as img.naturalWidth and
img.naturalHeight). -->
title="SVG image, no natural dimensions, and aspect ratio from viewBox"
data-density="none"
data-natural-width="300" data-natural-height="100"
data-width="720" data-height="240">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='400%' height='10%' viewBox='0 0 600 200'></svg>"
title="SVG image, percengage natural dimensions, and aspect ratio from viewBox"
data-density="none"
data-natural-width="300" data-natural-height="100"
data-width="720" data-height="240">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-400%' height='-10%' viewBox='0 0 600 200'></svg>"
title="SVG image, negative percengage natural dimensions, and aspect ratio from viewBox"
data-density="none"
data-natural-width="300" data-natural-height="100"
data-width="720" data-height="240">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 600 200'></svg>"
title="SVG image, with natural width, and aspect ratio from viewBox"
data-density="both"
data-natural-width="60" data-natural-height="20">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 600 200'></svg>"
title="SVG image, with natural height, and aspect ratio from viewBox"
data-density="both"
data-natural-width="180" data-natural-height="60">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='0' viewBox='0 0 600 200'></svg>"
title="SVG image, with natural width of 0, and aspect ratio from viewBox"
data-density="both"
data-natural-width="0" data-natural-height="0">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='0' viewBox='0 0 600 200'></svg>"
title="SVG image, with natural height of 0, and aspect ratio from viewBox"
data-density="both"
data-natural-width="0" data-natural-height="0">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5' viewBox='0 0 600 200'></svg>"
title="SVG image, with natural width being negative, and aspect ratio from viewBox"
data-density="none"
data-natural-width="300" data-natural-height="100"
data-width="720" data-height="240">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='-5' viewBox='0 0 600 200'></svg>"
title="SVG image, with natural height being negative, and aspect ratio from viewBox"
data-density="none"
data-natural-width="300" data-natural-height="100"
data-width="720" data-height="240">
<!-- Third group of SVG images: Check a degenerate 0-sized viewBox for some of the
cases; it should have no impact. -->
title="SVG image, no natural dimensions, viewBox with 0 width/height"
data-density="none"
data-natural-width="300" data-natural-height="150">
title="SVG image, no natural dimensions, viewBox with 0 width"
data-density="none"
data-natural-width="300" data-natural-height="150">
title="SVG image, no natural dimensions, viewBox with 0 height"
data-density="none"
data-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 0 0'></svg>"
title="SVG image, with natural width, viewBox with 0 width/height"
data-density="width"
data-natural-width="60" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 10 0'></svg>"
title="SVG image, with natural width, viewBox with 0 width"
data-density="width"
data-natural-width="60" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 0 10'></svg>"
title="SVG image, with natural width, viewBox with 0 height"
data-density="width"
data-natural-width="60" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 0 0'></svg>"
title="SVG image, with natural height, viewBox with 0 width/height"
data-density="height"
data-natural-width="300" data-natural-height="60">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 10 0'></svg>"
title="SVG image, with natural height, viewBox with 0 width"
data-density="height"
data-natural-width="300" data-natural-height="60">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 0 10'></svg>"
title="SVG image, with natural height, viewBox with 0 height"
data-density="height"
data-natural-width="300" data-natural-height="60">
<!--~- Final group of SVG images: we have pixel-valued width/height on the root
svg element, and possibly viewBox as well. The width and height attrs should
determine the natural dimensions, with no impact from viewBox. ---->
title="SVG image, with natural width and height"
data-density="both"
data-natural-width="60" data-natural-height="40">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' height='40' viewBox='0 0 600 200'></svg>"
title="SVG image, with natural width and height, and aspect ratio from viewBox"
data-density="both"
data-natural-width="60" data-natural-height="40">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='0' height='0' viewBox='0 0 600 200'></svg>"
title="SVG image, with natural width and height of 0, and aspect ratio from viewBox"
data-density="both"
data-natural-width="0" data-natural-height="0">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5' height='-5' viewBox='0 0 600 200'></svg>"
title="SVG image, with natural width and height being negative, and aspect ratio from viewBox"
data-density="none"
data-natural-width="300" data-natural-height="100"
data-width="720" data-height="240">
<!-- SVG images with intrinsic dimensions that happen to match the default
concrete object size (300x150). This group screens for a possible bug
where a browser recognizes 300 and/or 150 as "special" values and
declines to density-correct them, mistakenly assuming they came from
the default concrete object size rather than from the SVG's own
intrinsic dimensions. -->
title="SVG image, with natural width matching default concrete object size"
data-density="width"
data-natural-width="300" data-natural-height="150">
title="SVG image, with natural height matching default concrete object size"
data-density="height"
data-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='300' viewBox='0 0 300 150'></svg>"
title="SVG image, with natural width matching default concrete object size, and aspect ratio from viewBox"
data-density="both"
data-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='150' viewBox='0 0 300 150'></svg>"
title="SVG image, with natural height matching default concrete object size, and aspect ratio from viewBox"
data-density="both"
data-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='150'></svg>"
title="SVG image, with natural width and height matching default concrete object size"
data-density="both"
data-natural-width="300" data-natural-height="150">
</template>
</head>
<body>
<div id="scroller">
<div id="containingBlock">
</div>
</div>
<!-- We generate and append all of the tested <img> elements while we're inside
the <body>, so that all of the <img> elements' "load" events will block
the window onload event: -->
<script>
setup({explicit_done:true});
// Utility function to generate a clone of imgTemplates using "srcset" and a
// given density value, with expectations adjusted per the density:
function cloneTemplateWithDensity(density) {
if (typeof(density) !== "number" || density <= 0) {
// If we get here, there's a bug in the test itself; throw an exception:
throw new Error("test error: param should be a positive number");
}
let clone = imgTemplates.content.cloneNode("true");
for (let img of clone.children) {
// Swap out "src" for "srcset":
// The srcset attribute uses a space-separated list of tokens,
// so we need to encode any spaces that are in the URI itself
// before we put it in srcset:
let srcVal = img.getAttribute("src").replaceAll(" ", "%20");
img.removeAttribute("src");
img.setAttribute("srcSet", `${srcVal} ${density}x`);
// Mention the density in the 'title' to keep the title values unique:
img.setAttribute("title",
`${img.getAttribute("title")} (with srcset/${density}x)`);
// Determine which dimensions are density-corrected. For raster images
// (no data-density attribute), both dimensions are always corrected.
// For SVG images, only intrinsic (non-default) dimensions are corrected.
const densityAttr = img.dataset.density || "both";
const validDensityValues = ["none", "both", "width", "height"];
if (!validDensityValues.includes(densityAttr)) {
throw new Error(`test error: data-density="${densityAttr}" on "${img.getAttribute("title")}" is not a recognized value (expected one of: ${validDensityValues})`);
}
const scaleWidth = (densityAttr === "both" || densityAttr === "width");
const scaleHeight = (densityAttr === "both" || densityAttr === "height");
// Scale our 'data-natural-{width,height}' expectations by the density,
// but only for dimensions that are density-corrected (i.e., derived from
// the image's own intrinsic dimensions, not from the default object size).
// Also:
// * Preserve the original 'data-natural-{width,height}' as the
// 'data-not-rendered-{width,height}' expectation (if we don't already have
// one) since browsers don't do density-correction on .width and .height when
// the image is not being rendered, as discussed in
for (let name in img.dataset) {
if (name.startsWith("natural")) {
let origExpectation = img.dataset[name];
let isWidthAxis = (name == "naturalWidth");
let shouldScale = isWidthAxis ? scaleWidth : scaleHeight;
// Scale our img.natural{Width,Height} expectation:
if (shouldScale) {
img.dataset[name] = origExpectation / density;
}
// Construct a string for "data-not-rendered-{width,height}" for
// whichever axis we're currently handling, and stash the
// origExpectation in there if we don't already have some expectation
// set there:
let notRenderedName = name.replace("natural", "notRendered");
if (!(notRenderedName in img.dataset)) {
img.dataset[notRenderedName] = origExpectation;
}
}
}
}
return clone;
}
// Clone and append a copy of the contents of imgTemplates, for testing:
let clone = imgTemplates.content.cloneNode("true");
containingBlock.appendChild(clone);
// Append additional clones, modified to use srcset with specified density.
// Note:
// * '1' is the trivial case; we're just testing that for completeness,
// to be sure there aren't any unexpected differences between
// <img src="..."> and <img srcset="... 1x">).
// * It's best for whatever density we test here to be something that evenly
// divides all of the image sizes in this test (so 1 and 2 are easy choices).
containingBlock.appendChild(cloneTemplateWithDensity(1));
containingBlock.appendChild(cloneTemplateWithDensity(2));
// After all the img elements have loaded (indicated by the window load event),
// we run the various tests:
onload = function() {
Array.from(document.images).forEach(img => {
const expectedNaturalWidth = parseFloat(img.dataset.naturalWidth);
const expectedNaturalHeight = parseFloat(img.dataset.naturalHeight);
test(function() {
// We expect naturalWidth to match the provided data-natural-width
// (and similar for 'height').
assert_equals(img.naturalWidth, expectedNaturalWidth, 'naturalWidth');
assert_equals(img.naturalHeight, expectedNaturalHeight, 'naturalHeight');
let shouldCheckWidthAndHeight =
!img.hasAttribute("size-comes-from-broken-image-icon");
if (shouldCheckWidthAndHeight) {
// If 'data-width' is provided, then we expect img.width to match it.
// Otherwise we expect img.width to match the 'data-natural-width'.
// (And similar for 'height'.)
const expectedWidth = 'width' in img.dataset ?
parseFloat(img.dataset.width) : expectedNaturalWidth;
const expectedHeight = 'height' in img.dataset ?
parseFloat(img.dataset.height) : expectedNaturalHeight;
assert_equals(img.width, expectedWidth, 'width');
assert_equals(img.height, expectedHeight, 'height');
}
}, `${img.title}`);
test(function() {
// Now test what we get when the img is not rendered.
// * naturalWidth and naturalHeight shouldn't change.
// * width and height should generally match naturalWidth and
// naturalHeight. (Exceptions are indicated via the
// 'data-not-rendered-{width/height} attributes).
this.add_cleanup(function() {
img.style.display = "";
});
img.style.display = "none";
img.getBoundingClientRect(); // Flush layout.
assert_equals(img.naturalWidth, expectedNaturalWidth,
'naturalWidth when not rendered');
assert_equals(img.naturalHeight, expectedNaturalHeight,
'naturalHeight when not rendered');
const expectedNotRenderedWidth = 'notRenderedWidth' in img.dataset ?
parseFloat(img.dataset.notRenderedWidth) : expectedNaturalWidth;
const expectedNotRenderedHeight = 'notRenderedHeight' in img.dataset ?
parseFloat(img.dataset.notRenderedHeight) : expectedNaturalHeight;
assert_equals(img.width, expectedNotRenderedWidth,
'width when not rendered');
assert_equals(img.height, expectedNotRenderedHeight,
'height when not rendered');
}, `${img.title} (when not rendered)`);
});
done();
};
</script>
</body>