Source code
Revision control
Copy as Markdown
Other Tools
<!DOCTYPE html>
<html>
  <title>A scroll over an iframe should not terminate the wheel transaction</title>
  <script type="application/javascript" src="apz_test_utils.js"></script>
  <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
  <script src="/tests/SimpleTest/paint_listener.js"></script>
<head>
<style>
body {
  height: 250vh;
  width: 100%;
  margin: 0;
  padding: 0;
}
#spacer {
  height: 150px;
  width: 100vw;
  background: yellow;
}
#subframe {
  width: 80vw;
  height: 100vh;
}
</style>
</head>
<body>
  <div id="spacer"></div>
  <iframe id="subframe">
  </iframe>
</body>
<script>
const searchParams = new URLSearchParams(location.search);
const GESTURE_Y = 120;
async function scrollWithPan() {
  let transformEndPromise = promiseTransformEnd();
  await NativePanHandler.promiseNativePanEvent(
    window,
    150,
    GESTURE_Y,
    0,
    NativePanHandler.delta * 0.5,
    NativePanHandler.beginPhase,
  );
  // The iframe we need to scroll over is 30 CSS pixels lower than the original
  // gesture location. We need to perform at least one pan gesture update after
  // we have scrolled at least 30 CSS pixels.
  await SimpleTest.promiseWaitForCondition(async () => {
    let scrollOffset = window.scrollY;
    await NativePanHandler.promiseNativePanEvent(
      window,
      150,
      GESTURE_Y,
      0,
      NativePanHandler.delta * 0.5,
      NativePanHandler.updatePhase,
    );
    await promiseFrame();
    await promiseApzFlushedRepaints();
    return scrollOffset > 50;
  }, "Scroll at least once over the iframe");
  await NativePanHandler.promiseNativePanEvent(
    window,
    150,
    GESTURE_Y,
    0,
    NativePanHandler.delta,
    NativePanHandler.endPhase,
  );
  await transformEndPromise;
}
async function scrollWithWheel() {
  let transformEndPromise = promiseTransformEnd();
  await promiseMoveMouseAndScrollWheelOver(window, 150, GESTURE_Y, false, 20);
  // The iframe we need to scroll over is 30 CSS pixels lower than the original
  // gesture location. We need to perform at least one mousewheel scroll after
  // we have scrolled at least 30 CSS pixels.
  await SimpleTest.promiseWaitForCondition(async () => {
    let scrollOffset = window.scrollY;
    // While promiseMoveMouseAndScrollWheelOver uses a positive value to scroll
    // down, synthesizeNativeWheel uses a negative value to scroll down.
    await synthesizeNativeWheel(window, 150, GESTURE_Y, 0, -20, null);
    await promiseFrame();
    await promiseApzFlushedRepaints();
    return scrollOffset > 50;
  }, "Scroll at least once over the iframe");
  await transformEndPromise;
}
async function test() {
  let iframeURL =
       SimpleTest.getTestFileURL("helper_scroll_over_subframe_child.html");
  switch (searchParams.get("oop")) {
    case "true":
      break;
    default:
      break;
  }
  const iframeLoadPromise = promiseOneEvent(subframe, "load", null);
  subframe.src = iframeURL;
  await iframeLoadPromise;
  await SpecialPowers.spawn(subframe, [], async () => {
    await content.wrappedJSObject.waitUntilApzStable();
    await SpecialPowers.contentTransformsReceived(content);
  });
  let childWindowReceivedWheelEvent = false;
  window.addEventListener("message", e => {
    if (e.data == "child-received-wheel-event") {
      childWindowReceivedWheelEvent = true;
    }
  });
  await SpecialPowers.spawn(subframe, [], () => {
    let target = content.document.getElementById("target")
    target.style.backgroundColor = "green";
    content.getComputedStyle(target).backgroundColor;
    target.addEventListener("wheel", () => {
      target.style.backgroundColor = "red";
      content.getComputedStyle(target).backgroundColor;
    });
    return new Promise(resolve => resolve());
  });
  await promiseFrame();
  // Scroll over the iframe
  switch (searchParams.get("scroll")) {
    case "wheel":
      await scrollWithWheel();
      break;
    case "pan":
      await scrollWithPan();
      break;
    default:
      ok(false, "Unsupported scroll value: " + searchParams.get("scroll"));
      break;
  }
  // Wait an extra frame to ensure any message from the child has
  // extra time to be sent to the parent.
  await promiseFrame();
  let res = await SpecialPowers.spawn(subframe, [], () => {
    let target = content.document.getElementById("target")
    return target.style.backgroundColor;
  });
  await promiseFrame();
  // We should not have fired a wheel event to the element in the iframe
  ok(!childWindowReceivedWheelEvent, "Child window should not receive wheel events");
  is(res, "green", "OOP iframe does not halt user scroll of parent");
}
waitUntilApzStable().then(test).then(subtestDone, subtestFailed);
</script>
</html>