Source code
Revision control
Copy as Markdown
Other Tools
<!DOCTYPE HTML>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0">
<title>Tests that pending visual scroll positions on RSFs of non-RCDs get cleared properly</title>
<script src="apz_test_utils.js"></script>
<script src="apz_test_native_event_utils.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<body>
<iframe style="width: 300px; height: 300px" id="scroller"></iframe>
<script>
function populateScroller() {
  let text = '<div id="line0">line 0</div><br>';
  for (let i = 1; i < 100; i++) {
      text += 'line ' + i + '<br>';
  }
  document.querySelector('#scroller').contentDocument.body.innerHTML = text;
}
function reconstructScroller() {
  let scroller = document.querySelector('#scroller');
  scroller.style.display = 'none';
  /* eslint-disable no-unused-vars */
  let dummyToForceFlush = scroller.scrollTop;
  scroller.style.display = '';
  dummyToForceFlush = scroller.scrollTop;
}
async function test() {
  let scroller = document.querySelector('#scroller');
  let subwin = scroller.contentWindow;
  populateScroller();
  subwin.scrollTo(0, 100);
  is(subwin.scrollY, 100, 'Scroller scrolled down to y=100');
  // let the visual scroll position round-trip through APZ
  await promiseApzFlushedRepaints();
  // frame reconstruction does a ScrollToVisual. The bug is that the pending
  // visual scroll offset update never gets cleared even though the paint
  // transaction should clear it.
  reconstructScroller();
  await promiseApzFlushedRepaints();
  // Scroll back up to the top using APZ-side scrolling, and wait for the APZ
  // wheel animation to complete and the final scroll position to get synced
  // back to the main thread. The large -250 scroll delta required here is due
  await promiseMoveMouseAndScrollWheelOver(subwin, 10, 10, true, -250);
  let utils = SpecialPowers.getDOMWindowUtils(window);
  for (let i = 0; i < 60; i++) {
    utils.advanceTimeAndRefresh(16);
  }
  utils.restoreNormalRefresh();
  await promiseApzFlushedRepaints();
  is(subwin.scrollY, 0, 'Scroller scrolled up to y=0');
  // Do a mouse-drag-selection. I couldn't find any simpler way to reproduce
  // the problem.
  const kMouseMovePixels = 10;
  let promiseMouseMovesDone = new Promise((resolve) => {
    let mouseDownX = 0;
    subwin.document.documentElement.addEventListener('mousedown', (e) => {
      dump(`Got mousedown at ${e.screenX}\n`);
      mouseDownX = e.screenX;
    });
    subwin.document.documentElement.addEventListener('mousemove', (e) => {
      // Mousemove events can get squashed together so we check the coord
      // instead.
      dump(`Got mousemove at ${e.screenX}\n`);
      if (e.screenX - mouseDownX >= kMouseMovePixels) {
        resolve();
      }
    });
  });
  let line0 = subwin.document.querySelector('#line0');
  let dragFinisher = await promiseNativeMouseDrag(line0, 1, 5, kMouseMovePixels, 0, kMouseMovePixels);
  await promiseMouseMovesDone;
  await dragFinisher();
  is(subwin.scrollY, 0, 'Scroller should remain at y=0');
}
waitUntilApzStable()
.then(test)
.then(subtestDone, subtestFailed);
</script>