tor-browser

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

browser_layoutHelpers_getBoxQuads1.js (10685B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 // Tests getAdjustedQuads works properly in a variety of use cases including
      5 // iframes, scroll and zoom
      6 
      7 "use strict";
      8 
      9 const TEST_URI = TEST_URI_ROOT + "doc_layoutHelpers_getBoxQuads1.html";
     10 
     11 add_task(async function () {
     12  const tab = await addTab(TEST_URI);
     13 
     14  info("Running tests");
     15 
     16  await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
     17    // This function allows the Content Task to easily call `FullZoom` API in
     18    // the parent process.
     19    function sendCommand(cmd) {
     20      return SpecialPowers.spawnChrome([cmd], async data => {
     21        const window = this.browsingContext.topChromeWindow;
     22        switch (data) {
     23          case "zoom-enlarge":
     24            window.FullZoom.enlarge();
     25            break;
     26          case "zoom-reset":
     27            await window.FullZoom.reset();
     28            break;
     29          case "zoom-reduce":
     30            window.FullZoom.reduce();
     31            break;
     32        }
     33      });
     34    }
     35 
     36    const doc = content.document;
     37 
     38    const { require } = ChromeUtils.importESModule(
     39      "resource://devtools/shared/loader/Loader.sys.mjs"
     40    );
     41    const {
     42      getAdjustedQuads,
     43    } = require("resource://devtools/shared/layout/utils.js");
     44 
     45    Assert.strictEqual(
     46      typeof getAdjustedQuads,
     47      "function",
     48      "getAdjustedQuads is defined"
     49    );
     50 
     51    returnsTheRightDataStructure();
     52    isEmptyForMissingNode();
     53    isEmptyForHiddenNodes();
     54    defaultsToBorderBoxIfNoneProvided();
     55    returnsLikeGetBoxQuadsInSimpleCase();
     56    takesIframesOffsetsIntoAccount();
     57    takesScrollingIntoAccount();
     58    await takesZoomIntoAccount();
     59    returnsMultipleItemsForWrappingInlineElements();
     60 
     61    function returnsTheRightDataStructure() {
     62      info("Checks that the returned data contains bounds and 4 points");
     63 
     64      const node = doc.querySelector("body");
     65      const [res] = getAdjustedQuads(doc.defaultView, node, "content");
     66 
     67      ok("bounds" in res, "The returned data has a bounds property");
     68      ok("p1" in res, "The returned data has a p1 property");
     69      ok("p2" in res, "The returned data has a p2 property");
     70      ok("p3" in res, "The returned data has a p3 property");
     71      ok("p4" in res, "The returned data has a p4 property");
     72 
     73      for (const boundProp of [
     74        "bottom",
     75        "top",
     76        "right",
     77        "left",
     78        "width",
     79        "height",
     80        "x",
     81        "y",
     82      ]) {
     83        ok(
     84          boundProp in res.bounds,
     85          "The bounds has a " + boundProp + " property"
     86        );
     87      }
     88 
     89      for (const point of ["p1", "p2", "p3", "p4"]) {
     90        for (const pointProp of ["x", "y", "z", "w"]) {
     91          ok(
     92            pointProp in res[point],
     93            point + " has a " + pointProp + " property"
     94          );
     95        }
     96      }
     97    }
     98 
     99    function isEmptyForMissingNode() {
    100      info("Checks that null is returned for invalid nodes");
    101 
    102      for (const input of [null, undefined, "", 0]) {
    103        is(
    104          getAdjustedQuads(doc.defaultView, input).length,
    105          0,
    106          "A 0-length array is returned for input " + input
    107        );
    108      }
    109    }
    110 
    111    function isEmptyForHiddenNodes() {
    112      info("Checks that null is returned for nodes that aren't rendered");
    113 
    114      const style = doc.querySelector("#styles");
    115      is(
    116        getAdjustedQuads(doc.defaultView, style).length,
    117        0,
    118        "null is returned for a <style> node"
    119      );
    120 
    121      const hidden = doc.querySelector("#hidden-node");
    122      is(
    123        getAdjustedQuads(doc.defaultView, hidden).length,
    124        0,
    125        "null is returned for a hidden node"
    126      );
    127    }
    128 
    129    function defaultsToBorderBoxIfNoneProvided() {
    130      info(
    131        "Checks that if no boxtype is passed, then border is the default one"
    132      );
    133 
    134      const node = doc.querySelector("#simple-node-with-margin-padding-border");
    135      const [withBoxType] = getAdjustedQuads(doc.defaultView, node, "border");
    136      const [withoutBoxType] = getAdjustedQuads(doc.defaultView, node);
    137 
    138      for (const boundProp of [
    139        "bottom",
    140        "top",
    141        "right",
    142        "left",
    143        "width",
    144        "height",
    145        "x",
    146        "y",
    147      ]) {
    148        is(
    149          withBoxType.bounds[boundProp],
    150          withoutBoxType.bounds[boundProp],
    151          boundProp + " bound is equal with or without the border box type"
    152        );
    153      }
    154 
    155      for (const point of ["p1", "p2", "p3", "p4"]) {
    156        for (const pointProp of ["x", "y", "z", "w"]) {
    157          is(
    158            withBoxType[point][pointProp],
    159            withoutBoxType[point][pointProp],
    160            point +
    161              "." +
    162              pointProp +
    163              " is equal with or without the border box type"
    164          );
    165        }
    166      }
    167    }
    168 
    169    function returnsLikeGetBoxQuadsInSimpleCase() {
    170      info(
    171        "Checks that for an element in the main frame, without scroll nor zoom" +
    172          "that the returned value is similar to the returned value of getBoxQuads"
    173      );
    174 
    175      const node = doc.querySelector("#simple-node-with-margin-padding-border");
    176 
    177      for (const region of ["content", "padding", "border", "margin"]) {
    178        const expected = node.getBoxQuads({
    179          box: region,
    180        })[0];
    181        const [actual] = getAdjustedQuads(doc.defaultView, node, region);
    182 
    183        for (const boundProp of [
    184          "bottom",
    185          "top",
    186          "right",
    187          "left",
    188          "width",
    189          "height",
    190          "x",
    191          "y",
    192        ]) {
    193          is(
    194            actual.bounds[boundProp],
    195            expected.getBounds()[boundProp],
    196            boundProp +
    197              " bound is equal to the one returned by getBoxQuads for " +
    198              region +
    199              " box"
    200          );
    201        }
    202 
    203        for (const point of ["p1", "p2", "p3", "p4"]) {
    204          for (const pointProp of ["x", "y", "z", "w"]) {
    205            is(
    206              actual[point][pointProp],
    207              expected[point][pointProp],
    208              point +
    209                "." +
    210                pointProp +
    211                " is equal to the one returned by getBoxQuads for " +
    212                region +
    213                " box"
    214            );
    215          }
    216        }
    217      }
    218    }
    219 
    220    function takesIframesOffsetsIntoAccount() {
    221      info(
    222        "Checks that the quad returned for a node inside iframes that have " +
    223          "margins takes those offsets into account"
    224      );
    225 
    226      const rootIframe = doc.querySelector("iframe");
    227      const subIframe = rootIframe.contentDocument.querySelector("iframe");
    228      const innerNode = subIframe.contentDocument.querySelector("#inner-node");
    229 
    230      const [quad] = getAdjustedQuads(doc.defaultView, innerNode, "content");
    231 
    232      // rootIframe margin + subIframe margin + node margin + node border + node padding
    233      const p1x = 10 + 10 + 10 + 10 + 10;
    234      is(quad.p1.x, p1x, "The inner node's p1 x position is correct");
    235 
    236      // Same as p1x + the inner node width
    237      const p2x = p1x + 100;
    238      is(quad.p2.x, p2x, "The inner node's p2 x position is correct");
    239    }
    240 
    241    function takesScrollingIntoAccount() {
    242      info(
    243        "Checks that the quad returned for a node inside multiple scrolled " +
    244          "containers takes the scroll values into account"
    245      );
    246 
    247      // For info, the container being tested here is absolutely positioned at 0 0
    248      // to simplify asserting the coordinates
    249 
    250      info("Scroll the container nodes down");
    251      const scrolledNode = doc.querySelector("#scrolled-node");
    252      scrolledNode.scrollTop = 100;
    253      const subScrolledNode = doc.querySelector("#sub-scrolled-node");
    254      subScrolledNode.scrollTop = 200;
    255      const innerNode = doc.querySelector("#inner-scrolled-node");
    256 
    257      let [quad] = getAdjustedQuads(doc.defaultView, innerNode, "content");
    258      is(
    259        quad.p1.x,
    260        0,
    261        "p1.x of the scrolled node is correct after scrolling down"
    262      );
    263      is(
    264        quad.p1.y,
    265        -300,
    266        "p1.y of the scrolled node is correct after scrolling down"
    267      );
    268 
    269      info("Scrolling back up");
    270      scrolledNode.scrollTop = 0;
    271      subScrolledNode.scrollTop = 0;
    272 
    273      [quad] = getAdjustedQuads(doc.defaultView, innerNode, "content");
    274      is(
    275        quad.p1.x,
    276        0,
    277        "p1.x of the scrolled node is correct after scrolling up"
    278      );
    279      is(
    280        quad.p1.y,
    281        0,
    282        "p1.y of the scrolled node is correct after scrolling up"
    283      );
    284    }
    285 
    286    async function takesZoomIntoAccount() {
    287      info(
    288        "Checks that if the page is zoomed in/out, the quad returned is correct"
    289      );
    290 
    291      // Hard-coding coordinates in this zoom test is a bad idea as it can vary
    292      // depending on the platform, so we simply test that zooming in produces a
    293      // bigger quad and zooming out produces a smaller quad
    294 
    295      const node = doc.querySelector("#simple-node-with-margin-padding-border");
    296      const [defaultQuad] = getAdjustedQuads(doc.defaultView, node);
    297 
    298      info("Zoom in");
    299      await sendCommand("zoom-enlarge");
    300      const [zoomedInQuad] = getAdjustedQuads(doc.defaultView, node);
    301 
    302      Assert.greater(
    303        zoomedInQuad.bounds.width,
    304        defaultQuad.bounds.width,
    305        "The zoomed in quad is bigger than the default one"
    306      );
    307      Assert.greater(
    308        zoomedInQuad.bounds.height,
    309        defaultQuad.bounds.height,
    310        "The zoomed in quad is bigger than the default one"
    311      );
    312 
    313      info("Zoom out");
    314      await sendCommand("zoom-reset");
    315      await sendCommand("zoom-reduce");
    316 
    317      const [zoomedOutQuad] = getAdjustedQuads(doc.defaultView, node);
    318 
    319      Assert.less(
    320        zoomedOutQuad.bounds.width,
    321        defaultQuad.bounds.width,
    322        "The zoomed out quad is smaller than the default one"
    323      );
    324      Assert.less(
    325        zoomedOutQuad.bounds.height,
    326        defaultQuad.bounds.height,
    327        "The zoomed out quad is smaller than the default one"
    328      );
    329 
    330      await sendCommand("zoom-reset");
    331    }
    332 
    333    function returnsMultipleItemsForWrappingInlineElements() {
    334      info(
    335        "Checks that several quads are returned " +
    336          "for inline elements that span line-breaks"
    337      );
    338 
    339      const node = doc.querySelector("#inline");
    340      const quads = getAdjustedQuads(doc.defaultView, node, "content");
    341      // At least 3 because of the 2 <br />, maybe more depending on the window size.
    342      Assert.greaterOrEqual(quads.length, 3, "Multiple quads were returned");
    343 
    344      is(
    345        quads.length,
    346        node.getBoxQuads().length,
    347        "The same number of boxes as getBoxQuads was returned"
    348      );
    349    }
    350  });
    351 
    352  gBrowser.removeCurrentTab();
    353 });