tor-browser

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

mouseover-utils.js (3901B)


      1 let counter = 0;
      2 const loadImage = size => {
      3  return event => {
      4    let zoom;
      5    if (location.search.includes("replace")) {
      6      zoom = document.getElementById("image");
      7    } else {
      8      zoom = new Image();
      9    }
     10    zoom.src=`/images/lcp-${size}.png`;
     11    ++counter;
     12    zoom.elementTiming = "zoom" + counter;
     13    document.body.appendChild(zoom);
     14  }
     15 };
     16 const loadBackgroundImage = size => {
     17  return event => {
     18    const div = document.createElement("div");
     19    const [width, height] = size.split("x");
     20    ++counter;
     21    div.style = `background-image:
     22      url(/images/lcp-${size}.png?${counter}); width: ${width}px; height: ${height}px`;
     23    div.elementTiming = "zoom" + counter;
     24    document.body.appendChild(div);
     25  }
     26 };
     27 
     28 const registerMouseover = background => {
     29  const image = document.getElementById("image");
     30  const span = document.getElementById("span");
     31  const func = background ? loadBackgroundImage : loadImage;
     32  image.addEventListener("mouseover", func("100x50"));
     33  span.addEventListener("mouseover", func("256x256"));
     34 }
     35 
     36 const dispatch_mouseover = () => {
     37  span.dispatchEvent(new Event("mouseover"))
     38 };
     39 
     40 const wait_for_lcp_entries = async entries_expected => {
     41  await new Promise(resolve => {
     42    let entries_seen = 0;
     43    const PO = new PerformanceObserver(list => {
     44    const entries = list.getEntries();
     45      for (let entry of entries) {
     46        if (entry.url) {
     47          entries_seen++;
     48        }
     49      }
     50      if (entries_seen == entries_expected) {
     51        PO.disconnect();
     52        resolve()
     53      } else if (entries_seen > entries_expected) {
     54        PO.disconnect();
     55        reject();
     56      }
     57    });
     58    PO.observe({type: "largest-contentful-paint", buffered: true});
     59  });
     60 };
     61 const wait_for_element_timing_entry = async identifier => {
     62  await new Promise(resolve => {
     63    const PO = new PerformanceObserver(list => {
     64    const entries = list.getEntries();
     65      for (let entry of entries) {
     66        if (entry.identifier == identifier) {
     67          PO.disconnect();
     68          resolve()
     69        }
     70      }
     71    });
     72    PO.observe({type: "element", buffered: true});
     73  });
     74 };
     75 const wait_for_resource_timing_entry = async name => {
     76  await new Promise(resolve => {
     77    const PO = new PerformanceObserver(list => {
     78    const entries = list.getEntries();
     79      for (let entry of entries) {
     80        if (entry.name.includes(name)) {
     81          PO.disconnect();
     82          resolve()
     83        }
     84      }
     85    });
     86    PO.observe({type: "resource", buffered: true});
     87  });
     88 };
     89 
     90 const run_mouseover_test = background => {
     91  promise_test(async t => {
     92    // await the first LCP entry
     93    await wait_for_lcp_entries(1);
     94    // Hover over the image
     95    registerMouseover(background);
     96    if (test_driver) {
     97      await new test_driver.Actions().pointerMove(0, 0, {origin: image}).send();
     98    }
     99    if (!background) {
    100      await wait_for_element_timing_entry("zoom1");
    101    } else {
    102      await wait_for_resource_timing_entry("png?1");
    103      await new Promise(r => requestAnimationFrame(r));
    104    }
    105    // There's only a single LCP entry, because the zoom was skipped.
    106    await wait_for_lcp_entries(1);
    107 
    108    // Wait 600 ms as the heuristic is 500 ms.
    109    // This will no longer be necessary once the heuristic relies on Task
    110    // Attribution.
    111    await new Promise(r => step_timeout(r, 600));
    112 
    113    // Hover over the span.
    114    if (test_driver) {
    115      await new test_driver.Actions().pointerMove(0, 0, {origin: span}).send();
    116    }
    117    if (!background) {
    118      await wait_for_element_timing_entry("zoom2");
    119    } else {
    120      await wait_for_resource_timing_entry("png?2");
    121      await new Promise(r => requestAnimationFrame(r));
    122    }
    123    // There are 2 LCP entries, as the image loaded due to span hover is a
    124    // valid LCP candidate.
    125    await wait_for_lcp_entries(2);
    126  }, `LCP mouseover heuristics ignore ${background ?
    127        "background" : "element"}-based zoom widgets`);
    128 }