gfx/layers/apz/test/mochitest/helper_doubletap_zoom_smooth.html
author James Teh <jteh@mozilla.com>
Wed, 01 Feb 2023 05:02:01 +0000
changeset 651150 dd0fdd1daa69783be36acd5c50544f3694eaa8f9
parent 616557 918ef225713fa9fc188f42355a6cd4a2bfb3b64c
permissions -rw-r--r--
Bug 1813980: Check IsDoc before Parent in RemoteAccessibleBase::ApplyCrossDocOffset. r=morgan We call this function on every ancestor when calculating bounds. RemoteParent() currently requires a hash lookup, so it's more efficient to early return for !IsDoc() first. This is a micro-optimisation, but it might have some impact given that we call this on every ancestor, especially when hit testing, where we call Bounds() a lot. As a bit of drive-by cleanup, use RemoteParent() rather than calling Parent() and IsRemote/AsRemote(). Differential Revision: https://phabricator.services.mozilla.com/D168346

<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=2100"/>
  <title>Check that double tapping zoom out animation is smooth</title>
  <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
  <script type="application/javascript" src="apz_test_utils.js"></script>
  <script src="/tests/SimpleTest/paint_listener.js"></script>
  <script type="application/javascript">

let hasPrev = false;
let zoomingIn = true;
let lastVVLeft = 0, lastVVTop = 0, lastVVWidth = 0, lastVVHeight = 0;
let lastScrollX = 0, lastScrollY = 0;
let lastResolution = 0;

function within(a, b, tolerance) {
  return (Math.abs(a-b) < tolerance);
}

async function afterpaint() {
  info("vv pos " + visualViewport.pageLeft + "," + visualViewport.pageTop);
  info("vv size " + visualViewport.width + "," + visualViewport.height);
  info("win scroll " + window.scrollX + "," + window.scrollY);
  info("res " + await getResolution());
  if (hasPrev) {
    ok(zoomingIn ?
         lastVVLeft <= visualViewport.pageLeft :
         lastVVLeft >= visualViewport.pageLeft,
         "vvleft monotonic");
    // When zooming in pageTop stays 0, when zooming out (at least on mac)
    // the final value of pageTop is 2.5. Hence why the direction of these
    // inequalities.
    ok(zoomingIn ?
         lastVVTop >= visualViewport.pageTop :
         lastVVTop <= visualViewport.pageTop,
         "vvtop monotonic");
    ok(zoomingIn ?
         lastVVWidth >= visualViewport.width :
         lastVVWidth <= visualViewport.width,
         "vvwidth monotonic");
    ok(zoomingIn ?
         lastVVHeight >= visualViewport.height :
         lastVVHeight <= visualViewport.height,
         "vvheight monotonic");
    ok(zoomingIn ?
         lastScrollX <= window.scrollX :
         lastScrollX >= window.scrollX,
         "scrollx monotonic");
    if (!within(lastScrollY, window.scrollY, 2)) {
      ok(zoomingIn ?
           lastScrollY >= window.scrollY :
           lastScrollY <= window.scrollY,
           "scrolly monotonic");
    }

    // At the upper and lower limits of zoom constraints we can briefly go over
    // the limit and then back because of floating point inaccuracies.
    // In apzc callback helper we set the new content resolution to
    // (last presshell resolution that apz knows about) * (apz async zoom)
    // and (apz async zoom) is calculated as (apz zoom) / (last content resolution that apz knows about)
    // and (last content resolution that apz knows about) = (dev pixels per css pixel) * (ps resolution) * (resolution induced by transforms)
    // For simplicity we can assume that (dev pixels per css pixel) == (resolution induced by transforms) == 1
    // and (ps resolution) == (last presshell resolution that apz knows about).
    // The calculation then boils down to
    // (ps resolution) * ((apz zoom) / (ps resolution))
    // The fact that we divide by (ps resolution) first, and then multiply by
    // it means the result is not quite equal to (apz zoom).
    const deviceScale = window.devicePixelRatio;
    const maxZoom = 10.0;
    if (!within(lastResolution, maxZoom/deviceScale, 0.0001) &&
        !within(await getResolution(), maxZoom/deviceScale, 0.0001) &&
        !within(lastResolution, 1, 0.0001) &&
        !within(await getResolution(), 1, 0.0001)) {
      ok(zoomingIn ?
           lastResolution <= await getResolution() :
           lastResolution >= await getResolution(),
           "resolution monotonic");
    }

  } else {
    hasPrev = true;
  }
  lastVVLeft = visualViewport.pageLeft;
  lastVVTop = visualViewport.pageTop;
  lastVVWidth = visualViewport.width;
  lastVVHeight = visualViewport.height;
  lastScrollX = window.scrollX;
  if (!within(lastScrollY, window.scrollY, 2)) {
    lastScrollY = window.scrollY;
  }
  lastResolution = await getResolution();
}

async function test() {
  let useTouchpad = (location.search == "?touchpad");

  info("dpi: " + window.devicePixelRatio);

  window.addEventListener("MozAfterPaint", afterpaint);
  let intervalID = setInterval(afterpaint, 16);

  let resolution = await getResolution();
  ok(resolution > 0,
     "The initial_resolution is " + resolution + ", which is some sane value");

  // Check that double-tapping once on a small element zooms in
  info("sending first double tap");
  await doubleTapOn(document.getElementById("target2"), 10, 10, useTouchpad);
  let prev_resolution = resolution;
  resolution = await getResolution();
  ok(resolution > prev_resolution, "The first double-tap has increased the resolution to " + resolution);

  await promiseApzFlushedRepaints();

  hasPrev = false;
  zoomingIn = false;

  // Double tap, this won't hit anything but the body/html, and so will zoom us out.
  info("sending second double tap");
  await doubleTapOn(document.getElementById("target2"), 5, 65, useTouchpad);
  await promiseApzFlushedRepaints();
  prev_resolution = resolution;
  resolution = await getResolution();
  ok(resolution < prev_resolution, "The second double-tap has decreased the resolution to " + resolution);

  clearInterval(intervalID);
  window.removeEventListener("MozAfterPaint", afterpaint);
}

waitUntilApzStable()
.then(test)
.then(subtestDone, subtestFailed);

  </script>
  <style>
    .container {
      background-color: #eee;
      width: 95vw;
      height: 400vh;
    }
    .smallcontainer {
      background-color: #aaa;
      width: 40px;
      height: 40px;
      position: absolute;
      right: 0;
      top: 20px;
    }
</style>
</head>
<body>

<div id="target" class="container">
</div>
<div id="target2" class="smallcontainer">
</div>

</body>
</html>