tor-browser

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

util.js (3197B)


      1 // Utilities for Layout Instability tests.
      2 
      3 // Returns a promise that is resolved when the specified number of animation
      4 // frames has occurred.
      5 waitForAnimationFrames = frameCount => {
      6  return new Promise(resolve => {
      7    const handleFrame = () => {
      8      if (--frameCount <= 0)
      9        resolve();
     10      else
     11        requestAnimationFrame(handleFrame);
     12    };
     13    requestAnimationFrame(handleFrame);
     14  });
     15 };
     16 
     17 // Returns a promise that is resolved when the next animation frame occurs.
     18 waitForAnimationFrame = () => waitForAnimationFrames(1);
     19 
     20 // Helper to compute an expected layout shift score based on an expected impact
     21 // region and max move distance for a particular animation frame.
     22 computeExpectedScore = (impactRegionArea, moveDistance) => {
     23  const docElement = document.documentElement;
     24 
     25  const viewWidth = docElement.clientWidth;
     26  const viewHeight = docElement.clientHeight;
     27 
     28  const viewArea = viewWidth * viewHeight;
     29  const viewMaxDim = Math.max(viewWidth, viewHeight);
     30 
     31  const impactFraction = impactRegionArea / viewArea;
     32  const distanceFraction = moveDistance / viewMaxDim;
     33 
     34  return impactFraction * distanceFraction;
     35 };
     36 
     37 // An list to record all the entries with startTime and score.
     38 let watcher_entry_record = [];
     39 
     40 // An object that tracks the document cumulative layout shift score.
     41 // Usage:
     42 //
     43 //   const watcher = new ScoreWatcher;
     44 //   ...
     45 //   assert_equals(watcher.score, expectedScore);
     46 //
     47 // The score reflects only layout shifts that occur after the ScoreWatcher is
     48 // constructed.
     49 ScoreWatcher = function() {
     50  if (PerformanceObserver.supportedEntryTypes.indexOf("layout-shift") == -1)
     51    throw new Error("Layout Instability API not supported");
     52  this.score = 0;
     53  this.scoreWithInputExclusion = 0;
     54  const resetPromise = () => {
     55    this.promise = new Promise(resolve => {
     56      this.resolve = () => {
     57        resetPromise();
     58        resolve();
     59      }
     60    });
     61  };
     62  resetPromise();
     63  const observer = new PerformanceObserver(list => {
     64    list.getEntries().forEach(entry => {
     65      this.lastEntry = entry;
     66      this.score += entry.value;
     67      watcher_entry_record.push({startTime: entry.startTime, score: entry.value, hadRecentInput : entry.hadRecentInput});
     68      if (!entry.hadRecentInput)
     69        this.scoreWithInputExclusion += entry.value;
     70      this.resolve();
     71    });
     72  });
     73  observer.observe({entryTypes: ['layout-shift']});
     74 };
     75 
     76 ScoreWatcher.prototype.checkExpectation = function(expectation) {
     77  if (expectation.score != undefined)
     78    assert_equals(this.score, expectation.score);
     79  if (expectation.sources)
     80    check_sources(expectation.sources, this.lastEntry.sources);
     81 };
     82 
     83 ScoreWatcher.prototype.get_entry_record = function() {
     84  return watcher_entry_record;
     85 };
     86 
     87 check_sources = (expect_sources, actual_sources) => {
     88  assert_equals(expect_sources.length, actual_sources.length);
     89  let rect_match = (e, a) =>
     90      e[0] == a.x && e[1] == a.y && e[2] == a.width && e[3] == a.height;
     91  let match = e => a =>
     92      e.node === a.node &&
     93      rect_match(e.previousRect, a.previousRect) &&
     94      rect_match(e.currentRect, a.currentRect);
     95  for (let e of expect_sources)
     96    assert_true(actual_sources.some(match(e)), e.node + " not found");
     97 };