tor-browser

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

baseline-alignment-and-overflow.tentative.html (10459B)


      1 <!DOCTYPE html>
      2 <title>HTML: widgets' baseline alignment and interaction with 'overflow'</title>
      3 <script src="/resources/testharness.js"></script>
      4 <script src="/resources/testharnessreport.js"></script>
      5 <!--
      6 This test tests where the baseline is for different widgets.
      7 This isn't yet specified, see https://github.com/whatwg/html/issues/5065
      8 
      9 Where the baseline is affects where *other* things on the same linebox are positioned. So this test
     10 makes assertions about the offsetTop for a previous sibling <span>, and compares it to a reference
     11 that has equivalent setup but using a styled <span> instead of an actual widget (where possible) so
     12 we can control where its baseline will be (assuming a correct CSS implementation).
     13 
     14 CSS has the following behavior regarding baselines (this is non-normative, also read the spec):
     15 
     16 * for a normal inline containing text, the baseline is the same as the text's baseline.
     17 * for replaced elements (like images), the baseline is at the bottom margin-box edge.
     18 * for an inline-block, it depends on its 'overflow':
     19  - 'visible': the baseline is the same as the baseline for the last line box in the inline-block.
     20  - otherwise: the baseline is like replaced elements.
     21 
     22 The baselines for different widgets, as implemented in Firefox, are as follows:
     23 
     24 <input type=text>
     25 <input type=search>
     26 <input type=tel>
     27 <input type=email>
     28 <input type=password>
     29 <input type=date>
     30 <input type=month>
     31 <input type=week>
     32 <input type=time>
     33 <input type=datetime-local>
     34 <input type=number>
     35 <input type=submit>
     36 <input type=reset>
     37 <input type=button>
     38   Like inline-block but 'overflow' is forced to 'visible' and text inside is vertically centered.
     39 
     40 <input type=checkbox> with 'appearance: auto'
     41 <input type=radio> with 'appearance: auto'
     42   At the bottom of the content-box edge (and whether there's a border depends
     43   on the platform).
     44 
     45   This is not usually how CSS works so we fake it with a negative margin-bottom.
     46 
     47 <input type=color>
     48   At the content-box edge.
     49 
     50 <input type=file>
     51   Like inline-block but 'overflow' is forced to to 'visible' and it contains a button; the button
     52   can affect where the baseline is.
     53 
     54 <input type=image> showing alt text, with 'overflow: visible'
     55   Like inline-block.
     56 
     57 <input type=image> showing an image
     58 <input type=image> showing alt text, with 'overflow' something other than 'visible'
     59 <input type=range>
     60 <input type=checkbox> with 'appearance: none'
     61 <input type=radio> with 'appearance: none'
     62   Like replaced elements.
     63 
     64 -->
     65 <style>
     66 .test {
     67  border-collapse: collapse;
     68  font-size: 10px;
     69 }
     70 .test td {
     71  border: none;
     72  padding: 0;
     73  margin:0;
     74  outline: 1px solid silver;
     75 }
     76 
     77 .test td > input,
     78 .ref td > .fake-input-text,
     79 .ref td > .inline-block,
     80 .ref td > img,
     81 .ref td > button {
     82  font: inherit;
     83  height: 60px;
     84  width: 60px;
     85  padding: 10px;
     86  box-sizing: border-box;
     87  margin: 10px 0;
     88  /* Note: a border is not specified because that would imply 'appearance: none' for some widgets */
     89 }
     90 
     91 .ref button img {
     92  height: 100%;
     93  width: 100%;
     94  display: block;
     95 }
     96 
     97 /* Use inline-grid instead of inline-block here to more easily center the text inside */
     98 .ref .fake-input-text {
     99  display: inline-grid;
    100  border: 2px solid; /* 2px matches UA default style */
    101  align-items: center;
    102 }
    103 .ref .inline-block {
    104  display: inline-block;
    105 }
    106 
    107 .ref-file-input-like button {
    108  font-size: unset;
    109 }
    110 
    111 [style*="appearance: none;"] {
    112  -webkit-appearance: none; /* TODO(zcorpan) remove this when unprefixed appearance is supported */
    113 }
    114 </style>
    115 <div id="log"></div>
    116 <h2>refs</h2>
    117 <!--
    118 The first span's offsetTop is what we want to compare with the corresponding test's span's offsetTop.
    119 The sibling element is there to control where the baseline for the line box will be.
    120 -->
    121 <table class="test ref">
    122  <tr class="ref-text-input-like"><td><span>ref-text-input-like</span> <span class=fake-input-text>x</span>
    123  <tr class="ref-checkbox-input-appearance-auto-like"><td><span>ref-checkbox-input-appearance-auto-like</span> <img class=auto-checkbox src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAIAAAD3UuoiAAAAGklEQVQoz2Nk%2BP%2BfgRqAiYFKYNSgUYOGp0EA%2BQMCFrJdTgsAAAAASUVORK5CYII%3D">
    124  <tr class="ref-color-input-like"><td><span>ref-color-input-like</span> <button><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAIAAAD3UuoiAAAAGklEQVQoz2Nk%2BP%2BfgRqAiYFKYNSgUYOGp0EA%2BQMCFrJdTgsAAAAASUVORK5CYII%3D"></button>
    125  <tr class="ref-file-input-like"><td><span>ref-file-input-like</span> <span class=inline-block><button>x</button></span>
    126  <tr class="ref-image-input-showing-alt-overflow-visible-like"><td><span>ref-image-input-showing-alt-overflow-visible-like</span> <span class=inline-block>x</span>
    127  <tr class="ref-image-input-showing-image-like"><td><span>ref-image-input-showing-image-like</span> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAIAAAD3UuoiAAAAGklEQVQoz2Nk%2BP%2BfgRqAiYFKYNSgUYOGp0EA%2BQMCFrJdTgsAAAAASUVORK5CYII%3D">
    128 </table>
    129 <h2>template table</h2>
    130 <!--
    131 Each row in this table will be cloned into #test-table for each combination of styles to test.
    132 -->
    133 <table id="template-table">
    134  <tr><td><span>text</span> <input type=text value=x></td></tr>
    135  <tr><td><span>search</span> <input type=search value=x></td></tr>
    136  <tr><td><span>tel</span> <input type=tel value=x></td></tr>
    137  <tr><td><span>url</span> <input type=url value="data:,x"></td></tr>
    138  <tr><td><span>email</span> <input type=email value=x></td></tr>
    139  <tr><td><span>password</span> <input type=password value=x></td></tr>
    140  <tr><td><span>date</span> <input type=date value="2020-01-01"></td></tr>
    141  <tr><td><span>month</span> <input type=month value="2020-01"></td></tr>
    142  <tr><td><span>week</span> <input type=week value="2020-W01"></td></tr>
    143  <tr><td><span>time</span> <input type=time value="00:00"></td></tr>
    144  <tr><td><span>datetime-local</span> <input type=datetime-local value="2020-01-01T00:00"></td></tr>
    145  <tr><td><span>number</span> <input type=number value=0></td></tr>
    146  <tr><td><span>range</span> <input type=range></td></tr>
    147  <tr><td><span>color</span> <input type=color value=#000000></td></tr>
    148  <tr><td><span>checkbox</span> <input type=checkbox></td></tr>
    149  <tr><td><span>radio</span> <input type=radio></td></tr>
    150  <tr><td><span>file</span> <input type=file></td></tr>
    151  <tr><td><span>submit</span> <input type=submit value=x></td></tr>
    152  <tr><td><span>image</span> <input type=image src="data:,broken" alt="x"></td></tr>
    153  <tr><td><span>image-with-src</span> <input type=image src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAIAAAD3UuoiAAAAGklEQVQoz2Nk%2BP%2BfgRqAiYFKYNSgUYOGp0EA%2BQMCFrJdTgsAAAAASUVORK5CYII%3D" alt="x"></td></tr>
    154  <tr><td><span>reset</span> <input type=reset value=x></td></tr>
    155  <tr><td><span>button</span> <input type=button value=x></td></tr>
    156 </table>
    157 <h2>tests</h2>
    158 <!--
    159 This table gets populated by the script.
    160 -->
    161 <table class="test" id="test-table"><tbody></tbody></table>
    162 <script>
    163  "use strict";
    164 
    165  promise_setup(async () => {
    166    const templateTable = document.querySelector('#template-table');
    167    const testTBody = document.querySelector('#test-table tbody');
    168 
    169    {
    170      const checkboxBorder = getComputedStyle(document.querySelector("input[type=checkbox]")).borderTopWidth;
    171      const checkboxLike = document.querySelector(".auto-checkbox");
    172      checkboxLike.style.border = checkboxBorder + " solid";
    173      checkboxLike.style.marginBottom = "-" + checkboxBorder;
    174    }
    175 
    176    const templateRows = templateTable.querySelectorAll('tr');
    177    for (const templateRow of templateRows) {
    178      for (const appearanceValue of ["auto", "none"]) {
    179        for (const overflowValue of ['visible', 'hidden', 'scroll']) {
    180          const clonedRow = templateRow.cloneNode(true);
    181          clonedRow.querySelector('input').setAttribute('style', `overflow: ${overflowValue}; appearance: ${appearanceValue};`);
    182          testTBody.append(clonedRow);
    183        }
    184      }
    185    }
    186 
    187    // wait for images to load
    188    await new Promise(resolve => window.onload = e => resolve());
    189    for (const img of document.images) {
    190      assert_true(img.complete); // either error state or loaded
    191    }
    192 
    193    // get layout info from refs
    194    const refTextInputLikeOffsetTop = document.querySelector('.ref-text-input-like span').offsetTop;
    195    const refCheckboxInputAppearanceAutoLikeOffsetTop = document.querySelector('.ref-checkbox-input-appearance-auto-like span').offsetTop;
    196    const refColorInputLikeOffsetTop = document.querySelector('.ref-color-input-like span').offsetTop;
    197    const refFileInputLikeOffsetTop = document.querySelector('.ref-file-input-like span').offsetTop;
    198    const refImageInputShowingAltOverflowVisibleLikeOffsetTop = document.querySelector('.ref-image-input-showing-alt-overflow-visible-like span').offsetTop;
    199    const refImageInputShowingImageLikeOffsetTop = document.querySelector('.ref-image-input-showing-image-like span').offsetTop;
    200 
    201    function expectedOffsetTop(input) {
    202      // TODO(zcorpan) https://github.com/whatwg/html/issues/5065
    203      // for now this is intended to match Firefox
    204      const style = input.getAttribute('style');
    205      const src = input.getAttribute('src');
    206      switch (input.type) {
    207        case 'file':
    208          return refFileInputLikeOffsetTop;
    209        case 'range':
    210          return refImageInputShowingImageLikeOffsetTop;
    211        case 'color':
    212          return refColorInputLikeOffsetTop;
    213        case 'checkbox':
    214        case 'radio':
    215          return (style.includes('appearance: none;')) ? refImageInputShowingImageLikeOffsetTop : refCheckboxInputAppearanceAutoLikeOffsetTop;
    216        case 'image':
    217          return (src === 'data:,broken' && style.includes('overflow: visible;')) ? refImageInputShowingAltOverflowVisibleLikeOffsetTop : refImageInputShowingImageLikeOffsetTop;
    218        default:
    219          return refTextInputLikeOffsetTop;
    220      }
    221    }
    222 
    223    function testName(markup) {
    224      return markup.replace(/data:image\/png[^"]+/, 'data:(png)');
    225    }
    226 
    227    for (const row of testTBody.children) {
    228      const input = row.firstChild.lastElementChild;
    229      // This is not using test() because promise_setup() only allows promise_test().
    230      promise_test(async () => {
    231        assert_equals(input.type, input.getAttribute('type'), 'input type should be supported')
    232        const offsetTopActual = row.firstChild.firstChild.offsetTop;
    233        assert_equals(offsetTopActual, expectedOffsetTop(input), '<span>.offsetTop');
    234      }, testName(input.outerHTML));
    235    }
    236  });
    237 </script>