tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

naturalWidth-naturalHeight-width-height.tentative.html (20557B)


      1 <!doctype html>
      2 <head>
      3 <meta charset="utf-8">
      4 <title>HTMLImageElement attributes naturalWidth, naturalHeight, width, height</title>
      5 <!-- Note: this test asserts a different expectation from what the HTML spec
      6     requires, as of mid-2025 when this testcase is being written. The spec
      7     behavior doesn't appear to be web-compatible for some of the cases here,
      8     and issue https://github.com/whatwg/html/issues/11287 is filed on
      9     addresing that.  In the meantime, this test is named with ".tentative" to
     10     indicate that it's not authoritative. After the spec change is accepted,
     11     we can remove the neighboring naturalWidth-naturalHeight.html test which
     12     asserts the prior spec text's expectations, since this test covers the
     13     same ground but with its expectations set according to the
     14     soon-to-be-updated spec text.  -->
     15 <link rel="help" href="https://github.com/whatwg/html/issues/11287">
     16 <link rel="help" href="https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-naturalwidth-dev">
     17 <link rel="help" href="https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-width">
     18 <link rel="help" href="https://html.spec.whatwg.org/multipage/images.html#density-corrected-intrinsic-width-and-height">
     19 <link rel="help" href="https://drafts.csswg.org/css-images/#natural-dimensions">
     20 <script src="/resources/testharness.js"></script>
     21 <script src="/resources/testharnessreport.js"></script>
     22 <style>
     23 #scroller {
     24  /* We wrap all the test content in a scroller so that it doesn't push
     25   * the textual test-results too far out of view.
     26   */
     27  border: 1px solid black;
     28  height: 400px;
     29  width: max-content;
     30  overflow: scroll;
     31 }
     32 #containingBlock {
     33  /* There are a few SVG images here that size so that their margin-box fills
     34   * their containing block width. We define a specific size here so that we
     35   * can then check for it (minus the margins) in the "data-width" attribute.
     36   */
     37  width: 740px;
     38 }
     39 img {
     40  /* This styling is just cosmetic, to help visualize the images. */
     41  border: 5px solid teal;
     42  margin: 5px;
     43  display: block;
     44 }
     45 </style>
     46 <!-- We specify the img elements in a <template> and then clone them for
     47     testing, so that we can dynamically generate and test several variants
     48     of each img. -->
     49 <template id="imgTemplates">
     50 <!-- For each img element:
     51     * The "data-natural-{width,height}" attributes represent the expected
     52     values of the img element's "naturalWidth" and "naturalHeight" IDL
     53     attributes. This test implicitly expects the "width" and "height" IDL
     54     attributes to have those same expected values; but in cases where that's
     55     not correct, we provide the actual expected value in the
     56     "data-{width,height}" attributes (as distinguished from
     57     data-natural-{width,height}).
     58     * The "title" attribute is a description of the scenario being tested, and
     59     it must be unique to satisfy the test harness requirements. -->
     60 
     61 <!-- JPG images -->
     62 <img src="resources/cat.jpg"
     63     title="raster image"
     64     data-natural-width="320" data-natural-height="240">
     65 <img src="resources/cat.jpg" width="10" height="10"
     66     title="raster image with width/height attributes"
     67     data-natural-width="320" data-natural-height="240"
     68     data-width="10" data-height="10"
     69     data-not-rendered-width="10" data-not-rendered-height="10">
     70 <!-- Use "size-comes-from-broken-image-icon" attribute to opt out of checking
     71     img.width and img.height, because they come from the UA-dependent
     72     size of the broken image icon: -->
     73 <img src="non-existent.jpg"
     74     title="non existent image, no natural dimensions"
     75     data-natural-width="0" data-natural-height="0"
     76     size-comes-from-broken-image-icon>
     77 <img src="non-existent.jpg" width="10" height="10"
     78     title="non existent image with width/height attributes, no natural dimensions"
     79     data-natural-width="0" data-natural-height="0"
     80     data-width="10" data-height="10"
     81     data-not-rendered-width="10" data-not-rendered-height="10">
     82 
     83 <!-- First group of SVG images: no viewBox, with a missing (or edge-casey, i.e.
     84     negative or percent-valued) value for the width and/or height attr on the
     85     root svg element in a SVG image. -->
     86 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"
     87     title="SVG image, no natural dimensions"
     88     data-natural-width="300" data-natural-height="150">
     89 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"
     90     width="40" height="10"
     91     data-width="40" data-height="10"
     92     data-not-rendered-width="40" data-not-rendered-height="10"
     93     title="SVG image with width/height attrs, no natural dimensions"
     94     data-natural-width="300" data-natural-height="150">
     95 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"
     96     width="40"
     97     data-width="40" data-not-rendered-width="40"
     98     title="SVG image with width attr, no natural dimensions"
     99     data-natural-width="300" data-natural-height="150">
    100 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>"
    101     height="10"
    102     data-height="10" data-not-rendered-height="10"
    103     title="SVG image with height attr, no natural dimensions"
    104     data-natural-width="300" data-natural-height="150">
    105 <!-- Note: percent values can't be resolved when determining natural
    106     dimensions, so the exact percentage shouldn't matter. -->
    107 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='400%' height='10%'></svg>"
    108     title="SVG image, percengage natural dimensions"
    109     data-natural-width="300" data-natural-height="150">
    110 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-400%' height='-10%'></svg>"
    111     title="SVG image, negative percengage natural dimensions"
    112     data-natural-width="300" data-natural-height="150">
    113 <!-- If only one attribute is present, it should show up as a natural
    114     dimension, without influencing the other natural dimension. -->
    115 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60'></svg>"
    116     title="SVG image, with natural width"
    117     data-natural-width="60" data-natural-height="150">
    118 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60'></svg>"
    119     title="SVG image, with natural height"
    120     data-natural-width="300" data-natural-height="60">
    121 <!-- If either attribute is 0 or a negative length, it should show up as a
    122     natural dimension: of 0. -->
    123 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='0'></svg>"
    124     title="SVG image, with natural width of 0"
    125     data-natural-width="0" data-natural-height="150">
    126 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='0'></svg>"
    127     title="SVG image, with natural height of 0"
    128     data-natural-width="300" data-natural-height="0">
    129 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5'></svg>"
    130     title="SVG image, with natural width being negative"
    131     data-natural-width="300" data-natural-height="150">
    132 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='-5'></svg>"
    133     title="SVG image, with natural height being negative"
    134     data-natural-width="300" data-natural-height="150">
    135 
    136 <!-- Second group of SVG images: Same as above, but now with a viewBox that grants a
    137     3:1 aspect-ratio; whenever we know one natural dimension, that should
    138     combine with the aspect ratio to produce the other natural dimension.
    139 
    140     NOTE: for a few subtests here, the image ends up expanding to fill the
    141     containing block's width, i.e. rendering at a larger size than its natural
    142     size. In those cases, we include 'data-width' & 'data-height' attributes,
    143     so that this test's JS can validate that img.width and img.height return
    144     these expected larger values. (Otherwise, we expect img.width and
    145     img.height to return the same values as img.naturalWidth and
    146     img.naturalHeight). -->
    147 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 200'></svg>"
    148     title="SVG image, no natural dimensions, and aspect ratio from viewBox"
    149     data-natural-width="300" data-natural-height="100"
    150     data-width="720" data-height="240">
    151 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='400%' height='10%' viewBox='0 0 600 200'></svg>"
    152     title="SVG image, percengage natural dimensions, and aspect ratio from viewBox"
    153     data-natural-width="300" data-natural-height="100"
    154     data-width="720" data-height="240">
    155 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-400%' height='-10%' viewBox='0 0 600 200'></svg>"
    156     title="SVG image, negative percengage natural dimensions, and aspect ratio from viewBox"
    157     data-natural-width="300" data-natural-height="100"
    158     data-width="720" data-height="240">
    159 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 600 200'></svg>"
    160     title="SVG image, with natural width, and aspect ratio from viewBox"
    161     data-natural-width="60" data-natural-height="20">
    162 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 600 200'></svg>"
    163     title="SVG image, with natural height, and aspect ratio from viewBox"
    164     data-natural-width="180" data-natural-height="60">
    165 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='0' viewBox='0 0 600 200'></svg>"
    166     title="SVG image, with natural width of 0, and aspect ratio from viewBox"
    167     data-natural-width="0" data-natural-height="0">
    168 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='0' viewBox='0 0 600 200'></svg>"
    169     title="SVG image, with natural height of 0, and aspect ratio from viewBox"
    170     data-natural-width="0" data-natural-height="0">
    171 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5' viewBox='0 0 600 200'></svg>"
    172     title="SVG image, with natural width being negative, and aspect ratio from viewBox"
    173     data-natural-width="300" data-natural-height="100"
    174     data-width="720" data-height="240">
    175 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='-5' viewBox='0 0 600 200'></svg>"
    176     title="SVG image, with natural height being negative, and aspect ratio from viewBox"
    177     data-natural-width="300" data-natural-height="100"
    178     data-width="720" data-height="240">
    179 
    180 <!-- Third group of SVG images: Check a degenerate 0-sized viewBox for some of the
    181     cases; it should have no impact. -->
    182 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 0 0'></svg>"
    183     title="SVG image, no natural dimensions, viewBox with 0 width/height"
    184     data-natural-width="300" data-natural-height="150">
    185 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 0'></svg>"
    186     title="SVG image, no natural dimensions, viewBox with 0 width"
    187     data-natural-width="300" data-natural-height="150">
    188 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 0 10'></svg>"
    189     title="SVG image, no natural dimensions, viewBox with 0 height"
    190     data-natural-width="300" data-natural-height="150">
    191 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 0 0'></svg>"
    192     title="SVG image, with natural width, viewBox with 0 width/height"
    193     data-natural-width="60" data-natural-height="150">
    194 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 10 0'></svg>"
    195     title="SVG image, with natural width, viewBox with 0 width"
    196     data-natural-width="60" data-natural-height="150">
    197 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' viewBox='0 0 0 10'></svg>"
    198     title="SVG image, with natural width, viewBox with 0 height"
    199     data-natural-width="60" data-natural-height="150">
    200 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 0 0'></svg>"
    201     title="SVG image, with natural height, viewBox with 0 width/height"
    202     data-natural-width="300" data-natural-height="60">
    203 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 10 0'></svg>"
    204     title="SVG image, with natural height, viewBox with 0 width"
    205     data-natural-width="300" data-natural-height="60">
    206 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='60' viewBox='0 0 0 10'></svg>"
    207     title="SVG image, with natural height, viewBox with 0 height"
    208     data-natural-width="300" data-natural-height="60">
    209 
    210 <!~- Final group of SVG images: we have pixel-valued width/height on the root
    211     svg element, and possibly viewBox as well. The width and height attrs should
    212     determine the natural dimensions, with no impact from viewBox. -->
    213 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' height='40'></svg>"
    214     title="SVG image, with natural width and height"
    215     data-natural-width="60" data-natural-height="40">
    216 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='60' height='40' viewBox='0 0 600 200'></svg>"
    217     title="SVG image, with natural width and height, and aspect ratio from viewBox"
    218     data-natural-width="60" data-natural-height="40">
    219 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='0' height='0' viewBox='0 0 600 200'></svg>"
    220     title="SVG image, with natural width and height of 0, and aspect ratio from viewBox"
    221     data-natural-width="0" data-natural-height="0">
    222 <img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='-5' height='-5' viewBox='0 0 600 200'></svg>"
    223     title="SVG image, with natural width and height being negative, and aspect ratio from viewBox"
    224     data-natural-width="300" data-natural-height="100"
    225     data-width="720" data-height="240">
    226 </template>
    227 </head>
    228 <body>
    229 <div id="scroller">
    230  <div id="containingBlock">
    231  </div>
    232 </div>
    233 <!-- We generate and append all of the tested <img> elements while we're inside
    234     the <body>, so that all of the <img> elements' "load" events will block
    235     the window onload event: -->
    236 <script>
    237 setup({explicit_done:true});
    238 
    239 // Utility function to generate a clone of imgTemplates using "srcset" and a
    240 // given density value, with expectations adjusted per the density:
    241 function cloneTemplateWithDensity(density) {
    242  if (typeof(density) !== "number" || density <= 0) {
    243    // If we get here, there's a bug in the test itself; throw an exception:
    244    throw new Error("test error: param should be a positive number");
    245  }
    246  let clone = imgTemplates.content.cloneNode("true");
    247 
    248  for (let img of clone.children) {
    249    // Swap out "src" for "srcset":
    250    // The srcset attribute uses a space-separated list of tokens,
    251    // so we need to encode any spaces that are in the URI itself
    252    // before we put it in srcset:
    253    let srcVal = img.getAttribute("src").replaceAll(" ", "%20");
    254    img.removeAttribute("src");
    255    img.setAttribute("srcSet", `${srcVal} ${density}x`);
    256 
    257    // Mention the density in the 'title' to keep the title values unique:
    258    img.setAttribute("title",
    259                     `${img.getAttribute("title")} (with srcset/${density}x)`);
    260 
    261    const isUsingConcreteObjectWidth = (img.dataset.naturalWidth == "300");
    262    const isUsingConcreteObjectHeight = (img.dataset.naturalHeight == "150");
    263 
    264    // Scale our 'data-natural-{width,height}' expectations by the density.
    265    // But also:
    266    // * Preserve the original 'data-natural-{width,height}' as the
    267    // 'data-{width,height}' expectation if it's just the concrete object size
    268    // (which doesn't actually get scaled by the density in practice when
    269    // the image actually renders).
    270    // * Preserve the original 'data-natural-{width,height}' as the
    271    // 'data-not-rendered-{width,height}' expectation (if we don't already have
    272    // one) since browsers don't do density-correction on .width and .height when
    273    // the image is not being rendered, as discussed in
    274    // https://github.com/whatwg/html/issues/11287#issuecomment-2923467541
    275    for (let name in img.dataset) {
    276      if (name.startsWith("natural")) {
    277        let origExpectation = img.dataset[name];
    278 
    279        // Scale our img.natural{Width,Height} expectation:
    280        img.dataset[name] = origExpectation / density;
    281 
    282        let isWidthAxis = (name == "naturalWidth");
    283        let nameWithoutNatural = (isWidthAxis ? "width" : "height");
    284 
    285        let isConcreteObjectSize =
    286          (isWidthAxis ? isUsingConcreteObjectWidth : isUsingConcreteObjectHeight);
    287        if (isConcreteObjectSize && !(nameWithoutNatural in img.dataset)) {
    288          img.dataset[nameWithoutNatural] = origExpectation;
    289        }
    290 
    291        // Construct a string for "data-not-rendered-{width,height}" for
    292        // whichever axis we're currently handling, and stash the
    293        // origExpectation in there if we don't already have some expectation
    294        // set there:
    295        let notRenderedName = name.replace("natural", "notRendered");
    296        if (!(notRenderedName in img.dataset)) {
    297          img.dataset[notRenderedName] = origExpectation;
    298        }
    299      }
    300    }
    301  }
    302  return clone;
    303 }
    304 
    305 // Clone and append a copy of the contents of imgTemplates, for testing:
    306 let clone = imgTemplates.content.cloneNode("true");
    307 containingBlock.appendChild(clone);
    308 
    309 // Append additional clones, modified to use srcset with specified density.
    310 // Note:
    311 //  * '1' is the trivial case; we're just testing that for completeness,
    312 //    to be sure there aren't any unexpected differences between
    313 //    <img src="..."> and <img srcset="... 1x">).
    314 //  * It's best for whatever density we test here to be something that evenly
    315 //    divides all of the image sizes in this test (so 1 and 2 are easy choices).
    316 containingBlock.appendChild(cloneTemplateWithDensity(1));
    317 containingBlock.appendChild(cloneTemplateWithDensity(2));
    318 
    319 // After all the img elements have loaded (indicated by the window load event),
    320 // we run the various tests:
    321 onload = function() {
    322  Array.from(document.images).forEach(img => {
    323    const expectedNaturalWidth = parseFloat(img.dataset.naturalWidth);
    324    const expectedNaturalHeight = parseFloat(img.dataset.naturalHeight);
    325 
    326    test(function() {
    327      // We expect naturalWidth to match the provided data-natural-width
    328      // (and similar for 'height').
    329      assert_equals(img.naturalWidth, expectedNaturalWidth, 'naturalWidth');
    330      assert_equals(img.naturalHeight, expectedNaturalHeight, 'naturalHeight');
    331 
    332      let shouldCheckWidthAndHeight =
    333          !img.hasAttribute("size-comes-from-broken-image-icon");
    334 
    335      if (shouldCheckWidthAndHeight) {
    336        // If 'data-width' is provided, then we expect img.width to match it.
    337        // Otherwise we expect img.width to match the 'data-natural-width'.
    338        // (And similar for 'height'.)
    339        const expectedWidth = 'width' in img.dataset ?
    340              parseFloat(img.dataset.width) : expectedNaturalWidth;
    341        const expectedHeight = 'height' in img.dataset ?
    342              parseFloat(img.dataset.height) : expectedNaturalHeight;
    343        assert_equals(img.width, expectedWidth, 'width');
    344        assert_equals(img.height, expectedHeight, 'height');
    345      }
    346    }, `${img.title}`);
    347 
    348    test(function() {
    349      // Now test what we get when the img is not rendered.
    350      // * naturalWidth and naturalHeight shouldn't change.
    351      // * width and height should generally match naturalWidth and
    352      // naturalHeight. (Exceptions are indicated via the
    353      // 'data-not-rendered-{width/height} attributes).
    354      this.add_cleanup(function() {
    355        img.style.display = "";
    356      });
    357 
    358      img.style.display = "none";
    359      img.getBoundingClientRect(); // Flush layout.
    360 
    361      assert_equals(img.naturalWidth, expectedNaturalWidth,
    362                    'naturalWidth when not rendered');
    363      assert_equals(img.naturalHeight, expectedNaturalHeight,
    364                    'naturalHeight when not rendered');
    365 
    366      const expectedNotRenderedWidth = 'notRenderedWidth' in img.dataset ?
    367            parseFloat(img.dataset.notRenderedWidth) : expectedNaturalWidth;
    368      const expectedNotRenderedHeight = 'notRenderedHeight' in img.dataset ?
    369            parseFloat(img.dataset.notRenderedHeight) : expectedNaturalHeight;
    370 
    371      assert_equals(img.width, expectedNotRenderedWidth,
    372                    'width when not rendered');
    373      assert_equals(img.height, expectedNotRenderedHeight,
    374                    'height when not rendered');
    375    }, `${img.title} (when not rendered)`);
    376  });
    377  done();
    378 };
    379 </script>
    380 </body>