tor-browser

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

test_flex_items.html (12084B)


      1 <!doctype html>
      2 <html>
      3 <head>
      4 <meta charset="utf-8">
      5 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
      6 <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
      7 <style>
      8  .container {
      9    display: flex;
     10    background-color: grey;
     11    font: 14px sans-serif;
     12    height: 50px;
     13  }
     14  #flex-sanity {
     15    /* This just needs to be large enough so that no shrinking is required. */
     16    width: 1600px;
     17  }
     18  .clamped-huge-item {
     19    flex: 1 1 1650px; /* This needs to be bigger than #flex-sanity, to test
     20                         the scenario it's aiming to test (early clamping of a
     21                         flex item which, if left unclamped, would've reversed
     22                         the direction of flexing & made everything shrink). */
     23    max-width: 10px;
     24  }
     25 
     26  .base        { align-self: baseline; }
     27  .lastbase    { align-self: last baseline; }
     28 
     29  .offset      { margin-top: 10px;
     30                 margin-bottom: 3px; }
     31 
     32  .lime        { background: lime;   }
     33  .yellow      { background: yellow; }
     34  .orange      { background: orange; }
     35  .pink        { background: pink;   }
     36  .tan         { background: tan;    }
     37  .white       { background: white;  }
     38 
     39  .crossMinMax { min-height: 40px;
     40                 max-height: 120px; }
     41 
     42  .mainMinMax  { min-width: 120px;
     43                 max-width: 500px; }
     44 
     45  .flexGrow    { flex-grow: 1; }
     46  .spacer150   { width: 150px;
     47                 box-sizing: border-box;
     48                 height: 10px;
     49                 border: 1px solid teal; }
     50 
     51 </style>
     52 
     53 <script>
     54 "use strict";
     55 
     56 SimpleTest.waitForExplicitFinish();
     57 
     58 const TEXT_NODE = Node.TEXT_NODE;
     59 
     60 function testItemMatchesExpectedValues(item, values, index) {
     61  if (typeof(values.node) != "undefined") {
     62    is(item.node, values.node, "Item index " + index + " has expected node.");
     63  }
     64 
     65  if (typeof(values.mainBaseSize) != "undefined") {
     66    is(item.mainBaseSize, values.mainBaseSize, "Item index " + index + " has expected mainBaseSize.");
     67  }
     68 
     69  if (typeof(values.mainDeltaSize) != "undefined") {
     70    is(item.mainDeltaSize, values.mainDeltaSize, "Item index " + index + " has expected mainDeltaSize.");
     71  }
     72 
     73  if (typeof(values.mainMinSize) != "undefined") {
     74    is(item.mainMinSize, values.mainMinSize, "Item index " + index + " has expected mainMinSize.");
     75  }
     76 
     77  if (typeof(values.mainMaxSize) != "undefined") {
     78    is(item.mainMaxSize, values.mainMaxSize, "Item index " + index + " has expected mainMaxSize.");
     79  } else {
     80    // If we didn't specify an expected mainMaxSize, then it's implied
     81    // that the max main-size property (max-width/max-height) is at its
     82    // default "none" value, which our FlexItem API represents as +infinity.
     83    is(item.mainMaxSize, Number.POSITIVE_INFINITY,
     84       "Item index " + index + " has expected (default) mainMaxSize.");
     85  }
     86 
     87  if (typeof(values.crossMinSize) != "undefined") {
     88    is(item.crossMinSize, values.crossMinSize, "Item index " + index + " has expected crossMinSize.");
     89  }
     90 
     91  if (typeof(values.crossMaxSize) != "undefined") {
     92    is(item.crossMaxSize, values.crossMaxSize, "Item index " + index + " has expected crossMaxSize.");
     93  } else {
     94    // As above for mainMaxSize, no-expected-value implies we expect +infinity.
     95    is(item.crossMaxSize, Number.POSITIVE_INFINITY,
     96       "Item index " + index + " has expected (default) crossMaxSize.");
     97  }
     98 }
     99 
    100 // Test for items in "flex-sanity" flex container:
    101 function testFlexSanity() {
    102  let container = document.getElementById("flex-sanity");
    103  let flex = container.getAsFlexContainer();
    104  let lines = flex.getLines();
    105  is(lines.length, 1, "Container should have expected number of lines.");
    106 
    107  let line = lines[0];
    108  let containerHeight = container.getBoundingClientRect().height;
    109  is(line.crossSize, containerHeight,
    110     "Line crossSize should equal the height of the container.");
    111 
    112  // We can't compare baselines precisely, so we'll just confirm that they
    113  // appear somewhere within the elements that determine them.
    114  // (This assumes the first rect is baseline-aligned.)
    115  let firstRect = container.firstElementChild.getBoundingClientRect();
    116  ok(line.firstBaselineOffset > firstRect.top &&
    117     line.firstBaselineOffset < firstRect.bottom,
    118     "Line firstBaselineOffset should land somewhere within the element " +
    119     "that determines it.");
    120 
    121  // For last baseline, it's measured from the bottom, so we have to compare
    122  // against the element bounds subtracted from the container height.
    123  // We use the first node which uses last-baseline ("lb") alignment to
    124  // provide the rect:
    125  let lbElem = document.querySelector(".lastbase");
    126  let lbElemBoundingRect = lbElem.getBoundingClientRect();
    127  ok(line.lastBaselineOffset > containerHeight - lbElemBoundingRect.bottom &&
    128     line.lastBaselineOffset < containerHeight - lbElemBoundingRect.top,
    129     "Line lastBaselineOffset should land somewhere within the element" +
    130     "that determines it.");
    131 
    132  let expectedValues = [
    133    { crossMinSize: 0 },
    134    { mainBaseSize: 100,
    135      mainDeltaSize: 0 },
    136    { crossMinSize: 40,
    137      crossMaxSize: 120,
    138      mainDeltaSize: 0 },
    139    { mainMinSize: 120,
    140      mainMaxSize: 500,
    141      mainDeltaSize: 0 },
    142    { mainMinSize: 120,
    143      mainMaxSize: 500,
    144      mainBaseSize: 150,
    145      mainDeltaSize: 0 },
    146    { mainBaseSize:  10,
    147      mainMaxSize:   5,
    148      mainDeltaSize: 0 },
    149    { mainBaseSize: 10,
    150      mainMinSize:  15,
    151      mainDeltaSize: 0 },
    152    { mainBaseSize: 50,
    153      mainMaxSize: 10 },
    154    { mainBaseSize: 1650,
    155      mainMaxSize: 10,
    156      mainDeltaSize: 0 },
    157    { mainDeltaSize: 0 },
    158    { /* final item is anonymous flex item */ },
    159  ];
    160 
    161  let items = line.getItems();
    162  is(items.length, expectedValues.length,
    163     "Line should have expected number of items.");
    164  is(items.length, container.children.length + 1,
    165     "Line should have as many items as the flex container has child elems, " +
    166     "plus 1 for anonymous flex item");
    167 
    168  for (let i = 0; i < items.length; ++i) {
    169    let item = items[i];
    170    let values = expectedValues[i];
    171    // set the expected node to the node we're currently iterating over,
    172    // except for:
    173    // - the display:contents element (whose item is its first child)
    174    // - the final item (which is an anonymous flex item around text)
    175    if (i < container.children.length) {
    176      let curElem = container.children[i];
    177      values.node = (curElem.style.display == "contents"
    178                     ? curElem.firstElementChild
    179                     : curElem);
    180    } else {
    181      is(container.lastChild.nodeType, TEXT_NODE,
    182         "container's last child should be a text node");
    183      values.node = container.lastChild;
    184    }
    185    testItemMatchesExpectedValues(item, values, i);
    186  }
    187 
    188  // Check that the delta size of the first item is (roughly) equal to the
    189  // actual size minus the base size.
    190  isfuzzy(items[0].mainDeltaSize, firstRect.width - items[0].mainBaseSize, 1e-4,
    191          "flex-grow item should have expected mainDeltaSize.");
    192 }
    193 
    194 // Test for items in "flex-growing" flex container:
    195 function testFlexGrowing() {
    196  let expectedValues = [
    197    { mainBaseSize:  10,
    198      mainDeltaSize: 10,
    199      mainMinSize:   35 },
    200    { mainBaseSize:  20,
    201      mainDeltaSize: 5,
    202      mainMinSize:   28 },
    203    { mainBaseSize:  30,
    204      mainDeltaSize: 7  },
    205    { mainBaseSize:  0,
    206      mainDeltaSize: 48,
    207      mainMaxSize:   20 },
    208  ];
    209 
    210  let container = document.getElementById("flex-growing");
    211  let items = container.getAsFlexContainer().getLines()[0].getItems();
    212  is(items.length, container.children.length,
    213     "Line should have as many items as the flex container has child elems");
    214 
    215  for (let i = 0; i < items.length; ++i) {
    216    let item = items[i];
    217    let values = expectedValues[i];
    218    testItemMatchesExpectedValues(item, values, i);
    219  }
    220 }
    221 
    222 function runTests() {
    223  testFlexSanity();
    224  testFlexGrowing();
    225  SimpleTest.finish();
    226 }
    227 </script>
    228 </head>
    229 
    230 <body onLoad="runTests();">
    231  <!-- First flex container to be tested: "flex-sanity".
    232       We test a few general things, e.g.:
    233       - accuracy of reported baselines.
    234       - accuracy of reported flex base size, min/max sizes, & trivial deltas.
    235       - flex items formation for display:contents subtrees & text nodes.
    236   -->
    237  <div id="flex-sanity" class="container">
    238    <div class="lime base flexGrow">one line (first)</div>
    239    <div class="yellow lastbase" style="width: 100px">one line (last)</div>
    240    <div class="orange offset lastbase crossMinMax">two<br/>lines and offset (last)</div>
    241    <div class="pink offset base mainMinMax">offset (first)</div>
    242    <!-- Inflexible item w/ content-derived flex base size, which has min/max
    243         but doesn't violate them: -->
    244    <div class="tan mainMinMax">
    245      <div class="spacer150"></div>
    246    </div>
    247    <!-- Inflexible item that is trivially clamped to smaller max-width: -->
    248    <div style="flex: 0 0 10px; max-width: 5px"></div>
    249    <!-- Inflexible item that is trivially clamped to larger min-width: -->
    250    <div style="flex: 0 0 10px; min-width: 15px"></div>
    251    <!-- Item that wants to grow but is trivially clamped to max-width
    252         below base size: -->
    253    <div style="flex: 1 1 50px; max-width: 10px"></div>
    254    <div class="clamped-huge-item"></div>
    255    <div style="display:contents">
    256      <div class="white">replaced</div>
    257    </div>
    258    anon item for text
    259  </div>
    260 
    261  <!-- Second flex container to be tested, with items that grow by specific
    262       predictable amounts. This ends up triggering 4 passes of the main
    263       flexbox layout algorithm loop - and note that for each item, we only
    264       report (via 'mainDeltaSize') the delta that it wanted in the *last pass
    265       of the loop before that item was frozen*.
    266 
    267       Here's what goes on in each pass (and the tentative deltas)
    268     * PASS 1
    269        - Available space = 120 - 10 - 20 - 30 - 0 = 60px.
    270        - Sum of flex values = 1+1+2+16 = 20. So 1 "share" is 60px/20 = 3px.
    271        - Deltas (space distributed): +3px, +3px, +6px, +48px
    272          VIOLATIONS:
    273            item0 is now 10+3 = 13px, which under its min
    274            item1 is now 20+3 = 23px, which under its min
    275            item3 is now 0+48 = 48px, which over its max
    276        - the magnitude of max-violations (how far we're out of bounds) exceeds
    277          magnitude of min-violations, so we prioritize the max-violations.
    278        - So we freeze item3 at its max-width, 20px, leaving its final "desired"
    279          mainDeltaSize at +48px from this pass.
    280 
    281     * PASS 2
    282        - Available space = 120 - 10 - 20 - 30 - 20 = 40px.
    283        - Sum of flex values = 1+1+2 = 4. So 1 "share" is 40px/4 = 10px.
    284        - Deltas (space distributed): +10px, +10px, +20px, +0px.
    285          VIOLATIONS:
    286            item0 is now 10+10 = 20px, which is under its min
    287        - So we freeze item0 at its min-width, 35px, leaving its final "desired"
    288          mainDeltaSize at +10px from this pass.
    289 
    290     * PASS 3
    291        - Available space = 120 - 35 - 20 - 30 - 20 = 15px.
    292        - Sum of flex values = 1+2 = 3. So 1 "share" is 15px/3 = 5px.
    293        - Deltas (space distributed): +0px, +5px, +10px, +0px.
    294          VIOLATIONS:
    295            item1 is now 20+5 = 25px, which is under its min
    296        - So we freeze item1 at its min-width, 28px, leaving its final "desired"
    297          mainDeltaSize at +5px from this pass.
    298 
    299     * PASS 4
    300        - Available space = 120 - 35 - 28 - 30 - 20 = 7px.
    301        - Sum of flex values = 2. So 1 "share" is 7px/2 = 3.5px
    302        - Deltas (space distributed): +0px, +0px, +7px, +0px.
    303          VIOLATIONS:
    304            None! (So, we'll be done after this pass!)
    305        - So we freeze item2 (the only unfrozen item) at its flexed size, 37px,
    306          and set its final "desired" mainDeltaSize to +7px from this pass.
    307        - And we're done!
    308       -->
    309  <div id="flex-growing" class="container" style="width: 120px">
    310    <div style="flex: 1 10px; min-width: 35px"></div>
    311    <div style="flex: 1 20px; min-width: 28px"></div>
    312    <div style="flex: 2 30px; min-width: 0"></div>
    313    <div style="flex: 16 0px; max-width: 20px"></div>
    314  </div>
    315 </body>
    316 </html>