tor-browser

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

getComputedStyle-insets.js (9578B)


      1 export const testEl = document.createElement("div");
      2 export const containerForInflow = document.createElement("div");
      3 export const containerForAbspos = document.createElement("div");
      4 export const containerForFixed = document.createElement("div");
      5 
      6 testEl.id = "test";
      7 containerForInflow.id = "container-for-inflow";
      8 containerForAbspos.id = "container-for-abspos";
      9 containerForFixed.id = "container-for-fixed";
     10 
     11 containerForInflow.appendChild(testEl);
     12 containerForAbspos.appendChild(containerForInflow);
     13 containerForFixed.appendChild(containerForAbspos);
     14 document.body.appendChild(containerForFixed);
     15 
     16 const stylesheet = document.createElement("style");
     17 stylesheet.textContent = `
     18  #container-for-inflow {
     19    /* Content area: 100px tall, 200px wide */
     20    height: 100px;
     21    width: 200px;
     22    padding: 1px 2px;
     23    border-width: 2px 4px;
     24    margin: 4px 8px;
     25  }
     26  #container-for-abspos {
     27    /* Padding area: 200px tall, 400px wide */
     28    height: 184px;
     29    width: 368px;
     30    padding: 8px 16px;
     31    border-width: 16px 32px;
     32    margin: 32px 64px;
     33    position: relative;
     34  }
     35  #container-for-fixed {
     36    /* Padding area: 300px tall, 600px wide */
     37    height: 172px;
     38    width: 344px;
     39    padding: 64px 128px;
     40    border-width: 128px 256px;
     41    margin: 256px 512px;
     42    position: absolute;
     43    transform: scale(1);
     44    visibility: hidden;
     45  }
     46  [id ^= container] {
     47    border-style: solid;
     48  }
     49 `;
     50 document.head.prepend(stylesheet);
     51 
     52 function runTestsWithWM(data, testWM, cbWM) {
     53  const {
     54    style,
     55    containingBlockElement,
     56    containingBlockArea,
     57    preservesPercentages,
     58    preservesAuto,
     59    canStretchAutoSize,
     60    staticPositionX,
     61    staticPositionY,
     62  } = data;
     63 
     64  let cbHeight = containingBlockElement ? containingBlockElement.clientHeight : NaN;
     65  let cbWidth = containingBlockElement ? containingBlockElement.clientWidth : NaN;
     66  if (containingBlockElement && containingBlockArea == "content") {
     67    const cs = getComputedStyle(containingBlockElement);
     68    cbHeight -= parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom);
     69    cbWidth -= parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight);
     70  }
     71 
     72  const staticPositionTop = cbWM.blockStart == "top" || cbWM.inlineStart == "top"
     73    ? staticPositionY : cbHeight - staticPositionY;
     74  const staticPositionLeft = cbWM.blockStart == "left" || cbWM.inlineStart == "left"
     75    ? staticPositionX : cbWidth - staticPositionX;
     76  const staticPositionBottom = cbWM.blockStart == "bottom" || cbWM.inlineStart == "bottom"
     77    ? staticPositionY : cbHeight - staticPositionY;
     78  const staticPositionRight = cbWM.blockStart == "right" || cbWM.inlineStart == "right"
     79    ? staticPositionX : cbWidth - staticPositionX;
     80 
     81  function serialize(declarations) {
     82    return Object.entries(declarations).map(([p, v]) => `${p}: ${v}; `).join("");
     83  }
     84 
     85  function wmName(wm) {
     86    return Object.values(wm.style).join(" ");
     87  }
     88 
     89  function checkStyle(declarations, expected, msg) {
     90    test(function() {
     91      testEl.style.cssText = style + "; " + serialize(Object.assign({}, declarations, testWM.style));
     92      if (containingBlockElement) {
     93        containingBlockElement.style.cssText = serialize(Object.assign({}, cbWM.style));
     94      }
     95      const cs = getComputedStyle(testEl);
     96      for (let [prop, value] of Object.entries(expected)) {
     97        assert_equals(cs[prop], value, `'${prop}'`);
     98      }
     99    }, `${wmName(testWM)} inside ${wmName(cbWM)} - ${msg}`);
    100 
    101    testEl.style.cssText = "";
    102    if (containingBlockElement) {
    103      containingBlockElement.style.cssText = "";
    104    }
    105  }
    106 
    107  checkStyle({
    108    top: "1px",
    109    left: "2px",
    110    bottom: "3px",
    111    right: "4px",
    112  }, {
    113    top: "1px",
    114    left: "2px",
    115    bottom: "3px",
    116    right: "4px",
    117  }, "Pixels resolve as-is");
    118 
    119  checkStyle({
    120    top: "1em",
    121    left: "2em",
    122    bottom: "3em",
    123    right: "4em",
    124    "font-size": "10px",
    125  }, {
    126    top: "10px",
    127    left: "20px",
    128    bottom: "30px",
    129    right: "40px",
    130  }, "Relative lengths are absolutized into pixels");
    131 
    132  if (preservesPercentages) {
    133    checkStyle({
    134      top: "10%",
    135      left: "25%",
    136      bottom: "50%",
    137      right: "75%",
    138    }, {
    139      top: "10%",
    140      left: "25%",
    141      bottom: "50%",
    142      right: "75%",
    143    }, "Percentages resolve as-is");
    144  } else {
    145    checkStyle({
    146      top: "10%",
    147      left: "25%",
    148      bottom: "50%",
    149      right: "75%",
    150    }, {
    151      top: cbHeight * 10 / 100 + "px",
    152      left: cbWidth * 25 / 100 + "px",
    153      bottom: cbHeight * 50 / 100 + "px",
    154      right: cbWidth * 75 / 100 + "px",
    155    }, "Percentages are absolutized into pixels");
    156 
    157    checkStyle({
    158      top: "calc(10% - 1px)",
    159      left: "calc(25% - 2px)",
    160      bottom: "calc(50% - 3px)",
    161      right: "calc(75% - 4px)",
    162    }, {
    163      top: cbHeight * 10 / 100 - 1 + "px",
    164      left: cbWidth * 25 / 100 - 2 + "px",
    165      bottom: cbHeight * 50 / 100 - 3 + "px",
    166      right: cbWidth * 75 / 100 - 4 + "px",
    167    }, "calc() is absolutized into pixels");
    168  }
    169 
    170  if (canStretchAutoSize) {
    171    // Force overconstraintment by setting size or with insets that would result in
    172    // negative size. Then the resolved value should be the computed one according to
    173    // https://drafts.csswg.org/cssom/#resolved-value-special-case-property-like-top
    174 
    175    checkStyle({
    176      top: "1px",
    177      left: "2px",
    178      bottom: "3px",
    179      right: "4px",
    180      height: "0px",
    181      width: "0px",
    182    }, {
    183      top: "1px",
    184      left: "2px",
    185      bottom: "3px",
    186      right: "4px",
    187    }, "Pixels resolve as-is when overconstrained");
    188 
    189    checkStyle({
    190      top: "100%",
    191      left: "100%",
    192      bottom: "100%",
    193      right: "100%",
    194    }, {
    195      top: cbHeight + "px",
    196      left: cbWidth + "px",
    197      bottom: cbHeight + "px",
    198      right: cbWidth + "px",
    199    }, "Percentages absolutize the computed value when overconstrained");
    200  }
    201 
    202  if (preservesAuto) {
    203    checkStyle({
    204      top: "auto",
    205      left: "auto",
    206      bottom: "3px",
    207      right: "4px",
    208    }, {
    209      top: "auto",
    210      left: "auto",
    211      bottom: "3px",
    212      right: "4px",
    213    }, "If start side is 'auto' and end side is not, 'auto' resolves as-is");
    214 
    215    checkStyle({
    216      top: "1px",
    217      left: "2px",
    218      bottom: "auto",
    219      right: "auto",
    220    }, {
    221      top: "1px",
    222      left: "2px",
    223      bottom: "auto",
    224      right: "auto",
    225    }, "If end side is 'auto' and start side is not, 'auto' resolves as-is");
    226 
    227    checkStyle({
    228      top: "auto",
    229      left: "auto",
    230      bottom: "auto",
    231      right: "auto",
    232    }, {
    233      top: "auto",
    234      left: "auto",
    235      bottom: "auto",
    236      right: "auto",
    237    }, "If opposite sides are 'auto', they resolve as-is");
    238  } else if (canStretchAutoSize) {
    239    checkStyle({
    240      top: "auto",
    241      left: "auto",
    242      bottom: "3px",
    243      right: "4px",
    244    }, {
    245      top: cbHeight - 3 + "px",
    246      left: cbWidth - 4 + "px",
    247      bottom: "3px",
    248      right: "4px",
    249    }, "If start side is 'auto' and end side is not, 'auto' resolves to used value");
    250 
    251    checkStyle({
    252      top: "1px",
    253      left: "2px",
    254      bottom: "auto",
    255      right: "auto",
    256    }, {
    257      top: "1px",
    258      left: "2px",
    259      bottom: cbHeight - 1 + "px",
    260      right: cbWidth - 2 + "px",
    261    }, "If end side is 'auto' and start side is not, 'auto' resolves to used value");
    262 
    263    checkStyle({
    264      top: "auto",
    265      left: "auto",
    266      bottom: "auto",
    267      right: "auto",
    268    }, {
    269      top: staticPositionTop + "px",
    270      left: staticPositionLeft + "px",
    271      bottom: staticPositionBottom + "px",
    272      right: staticPositionRight + "px",
    273    }, "If opposite sides are 'auto', they resolve to used value");
    274  } else {
    275    checkStyle({
    276      top: "auto",
    277      left: "auto",
    278      bottom: "3px",
    279      right: "4px",
    280    }, {
    281      top: "-3px",
    282      left: "-4px",
    283      bottom: "3px",
    284      right: "4px",
    285    }, "If start side is 'auto' and end side is not, 'auto' resolves to used value");
    286 
    287    checkStyle({
    288      top: "1px",
    289      left: "2px",
    290      bottom: "auto",
    291      right: "auto",
    292    }, {
    293      top: "1px",
    294      left: "2px",
    295      bottom: "-1px",
    296      right: "-2px",
    297    }, "If end side is 'auto' and start side is not, 'auto' resolves to used value");
    298 
    299    checkStyle({
    300      top: "auto",
    301      left: "auto",
    302      bottom: "auto",
    303      right: "auto",
    304    }, {
    305      top: "0px",
    306      left: "0px",
    307      bottom: "0px",
    308      right: "0px",
    309    }, "If opposite sides are 'auto', they resolve to used value");
    310  }
    311 }
    312 
    313 const writingModes = [{
    314  style: {
    315    "writing-mode": "horizontal-tb",
    316    "direction": "ltr",
    317  },
    318  blockStart: "top",
    319  blockEnd: "bottom",
    320  inlineStart: "left",
    321  inlineEnd: "right",
    322 }, {
    323  style: {
    324    "writing-mode": "horizontal-tb",
    325    "direction": "rtl",
    326  },
    327  blockStart: "top",
    328  blockEnd: "bottom",
    329  inlineStart: "right",
    330  inlineEnd: "left",
    331 }, {
    332  style: {
    333    "writing-mode": "vertical-lr",
    334    "direction": "ltr",
    335  },
    336  blockStart: "left",
    337  blockEnd: "right",
    338  inlineStart: "top",
    339  inlineEnd: "bottom",
    340 }, {
    341  style: {
    342    "writing-mode": "vertical-lr",
    343    "direction": "rtl",
    344  },
    345  blockStart: "left",
    346  blockEnd: "right",
    347  inlineStart: "bottom",
    348  inlineEnd: "top",
    349 }, {
    350  style: {
    351    "writing-mode": "vertical-rl",
    352    "direction": "ltr",
    353  },
    354  blockStart: "right",
    355  blockEnd: "left",
    356  inlineStart: "top",
    357  inlineEnd: "bottom",
    358 }, {
    359  style: {
    360    "writing-mode": "vertical-rl",
    361    "direction": "rtl",
    362  },
    363  blockStart: "right",
    364  blockEnd: "left",
    365  inlineStart: "bottom",
    366  inlineEnd: "top",
    367 }];
    368 
    369 export function runTests(data) {
    370  for (let testWM of writingModes) {
    371    for (let cbWM of writingModes) {
    372      runTestsWithWM(data, testWM, cbWM);
    373    }
    374  }
    375 }