Source code
Revision control
Copy as Markdown
Other Tools
<!DOCTYPE html>
<html id="html">
<title>Test for making sure that an instant scroll update on the main-thread is reflected to displayport</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="apz_test_utils.js"></script>
<script src="apz_test_native_event_utils.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<style>
html {
  overflow: scroll;
  scrollbar-width: none;
}
</style>
<body>
<div style="height: 50000px"></div>
</body>
<script>
// Displayport alignment multiplier calculation; see AsyncPanZoomController::GetDisplayportAlignmentMultiplier
function GetDisplayportAlignmentMultiplier(aBaseHeight) {
  return Math.min(aBaseHeight / 250, 8.0);
}
async function test() {
  const resolution = await getResolution();
  const deviceScale = window.devicePixelRatio;
  // Invoke scrollToVisual to diverge the visual scroll offset from the
  // layout scroll offset.
  const utils = SpecialPowers.getDOMWindowUtils(window);
  utils.scrollToVisual(0, 1000,
                       utils.UPDATE_TYPE_MAIN_THREAD,
                       utils.SCROLL_MODE_INSTANT);
  await promiseApzFlushedRepaints();
  const initialVisualOffset = visualViewport.offsetTop;
  info(`The visualViewport.offsetTop is now ${visualViewport.offsetTop}`);
  ok(visualViewport.offsetTop > 0, `The visual viewport has scrolled`);
  info(`The visualViewport.pageTop is now ${visualViewport.pageTop}`);
  const initialScrollY = window.scrollY;
  info(`The window.scrollY is now ${window.scrollY}`);
  ok(window.scrollY > 0, `The layout viewport has scrolled`);
  is(initialScrollY + initialVisualOffset, 1000,
     "The visual scroll offset + the layout scroll offset should equal to 1000");
  // Start in a requestAnimationFrame callback so that awaiting an additional
  // requestAnimationFrame callback should result a paint.
  await promiseFrame();
  const currentTime = document.timeline.currentTime;
  // Do an instant relative scroll operation on the main-thread.
  // NOTE: Until the next paint this scroll position update will not be sent
  // to APZ.
  window.scrollBy(0, 1000);
  // Wait a frame so that a paint should have happened.
  await promiseFrame();
  // Make sure now that refresh driver's time has advanced.
  ok(document.timeline.currentTime > currentTime,
    `${document.timeline.currentTime} > ${currentTime}`);
  // Displayport margins calculation; see DisplayPortMargins::GetRelativeToLayoutViewport
  const margin = initialVisualOffset * resolution * deviceScale;
  const clientHeightInScreen = document.documentElement.clientHeight * deviceScale;
  const multiplier = GetDisplayportAlignmentMultiplier(clientHeightInScreen);
  // These calculations need to be same as the ones in GetDisplayPortFromMarginsData().
  const currentScrollPosition = initialScrollY + 1000;
  const currentScrollPositionInScreen = currentScrollPosition * resolution * deviceScale;
  const notAlignedDisplayportPosition = currentScrollPositionInScreen + margin;
  const displayportAlignment = 128 * multiplier;
  const alignedDisplayportPosition =
      displayportAlignment * Math.floor(notAlignedDisplayportPosition / displayportAlignment);
  let displayport = getLastContentDisplayportFor(document.documentElement.id);
  isfuzzy(displayport.y,
     (alignedDisplayportPosition - currentScrollPositionInScreen) / (resolution * deviceScale),
     1.0 * deviceScale, // `getLastContentDisplayportFor` returns rounded interger values.
                        // `document.documentElement.clientHeight` also returns rounded values.
     "The displayport y should be reflecting the instant scroll distance");
}
// Scale 2.0x to diverge the visual scroll offset from the layout scroll
// offset by calling nsIDOMWindowUtils.scrollToVisual.
SpecialPowers.DOMWindowUtils.setResolutionAndScaleTo(2.0);
waitUntilApzStable()
.then(test)
.then(subtestDone, subtestFailed);
</script>
</html>