File: naturalWidth-naturalHeight-width-height.tentative.html

package info (click to toggle)
firefox 144.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,637,504 kB
  • sloc: cpp: 7,576,692; javascript: 6,430,831; ansic: 3,748,119; python: 1,398,978; xml: 628,810; asm: 438,679; java: 186,194; sh: 63,212; makefile: 19,159; objc: 13,086; perl: 12,986; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 53; csh: 10
file content (377 lines) | stat: -rw-r--r-- 20,421 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
<!doctype html>
<head>
<meta charset="utf-8">
<title>HTMLImageElement attributes naturalWidth, naturalHeight, width, height</title>
<!-- Note: this test asserts a different expectation from what the HTML spec
     requires, as of mid-2025 when this testcase is being written. The spec
     behavior doesn't appear to be web-compatible for some of the cases here,
     and issue https://github.com/whatwg/html/issues/11287 is filed on
     addresing that.  In the meantime, this test is named with ".tentative" to
     indicate that it's not authoritative. After the spec change is accepted,
     we can remove the neighboring naturalWidth-naturalHeight.html test which
     asserts the prior spec text's expectations, since this test covers the
     same ground but with its expectations set according to the
     soon-to-be-updated spec text.  -->
<link rel="help" href="https://github.com/whatwg/html/issues/11287">
<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/embedded-content.html#dom-img-width">
<link rel="help" href="https://html.spec.whatwg.org/multipage/images.html#density-corrected-intrinsic-width-and-height">
<link rel="help" href="https://drafts.csswg.org/css-images/#natural-dimensions">
<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 "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. -->
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"
     title="SVG image, no natural dimensions"
     data-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"
     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-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"
     width="40"
     data-width="40" data-not-rendered-width="40"
     title="SVG image with width attr, no natural dimensions"
     data-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"
     height="10"
     data-height="10" data-not-rendered-height="10"
     title="SVG image with height attr, no natural dimensions"
     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-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-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. -->
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60'></svg>"
     title="SVG image, with natural 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'></svg>"
     title="SVG image, with natural 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. -->
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='0'></svg>"
     title="SVG image, with natural width of 0"
     data-natural-width="0" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='0'></svg>"
     title="SVG image, with natural height of 0"
     data-natural-width="300" data-natural-height="0">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5'></svg>"
     title="SVG image, with natural width being negative"
     data-natural-width="0" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='-5'></svg>"
     title="SVG image, with natural height being negative"
     data-natural-width="300" data-natural-height="0">

<!-- 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). -->
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 200'></svg>"
     title="SVG image, no natural dimensions, and aspect ratio from viewBox"
     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-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-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-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-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-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-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-natural-width="0" data-natural-height="0">
<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-natural-width="0" data-natural-height="0">

<!-- Third group of SVG images: Check a degenerate 0-sized viewBox for some of the
     cases; it should have no impact. -->
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 0 0'></svg>"
     title="SVG image, no natural dimensions, viewBox with 0 width/height"
     data-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 0'></svg>"
     title="SVG image, no natural dimensions, viewBox with 0 width"
     data-natural-width="300" data-natural-height="150">
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 0 10'></svg>"
     title="SVG image, no natural dimensions, viewBox with 0 height"
     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-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-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-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-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-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-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. -->
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' height='40'></svg>"
     title="SVG image, with natural width and height"
     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-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-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-natural-width="0" data-natural-height="0">
</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)`);

    const isUsingConcreteObjectWidth = (img.dataset.naturalWidth == "300");
    const isUsingConcreteObjectHeight = (img.dataset.naturalHeight == "150");

    // Scale our 'data-natural-{width,height}' expectations by the density.
    // But also:
    // * Preserve the original 'data-natural-{width,height}' as the
    // 'data-{width,height}' expectation if it's just the concrete object size
    // (which doesn't actually get scaled by the density in practice when
    // the image actually renders).
    // * 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
    // https://github.com/whatwg/html/issues/11287#issuecomment-2923467541
    for (let name in img.dataset) {
      if (name.startsWith("natural")) {
        let origExpectation = img.dataset[name];

        // Scale our img.natural{Width,Height} expectation:
        img.dataset[name] = origExpectation / density;

        let isWidthAxis = (name == "naturalWidth");
        let nameWithoutNatural = (isWidthAxis ? "width" : "height");

        let isConcreteObjectSize =
          (isWidthAxis ? isUsingConcreteObjectWidth : isUsingConcreteObjectHeight);
        if (isConcreteObjectSize && !(nameWithoutNatural in img.dataset)) {
          img.dataset[nameWithoutNatural] = origExpectation;
        }

        // 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>