summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/test/mochitest/helper_fission_scroll_oopif.html
blob: 2911b1eaf0fe009b881f6c26910c5e746f027497 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <title>Test for async-scrolling an OOPIF and ensuring hit-testing still works</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="/tests/SimpleTest/paint_listener.js"></script>
  <script src="helper_fission_utils.js"></script>
  <script src="apz_test_utils.js"></script>
  <script src="apz_test_native_event_utils.js"></script>
  <script>

fission_subtest_init();

FissionTestHelper.startTestPromise
  .then(waitUntilApzStable)
  .then(loadOOPIFrame("testframe", "helper_fission_empty.html"))
  .then(waitUntilApzStable)
  .then(test)
  .then(FissionTestHelper.subtestDone, FissionTestHelper.subtestFailed);


let code_for_oopif_to_run = function() {
  document.addEventListener("click", function(e) {
    dump(`OOPIF got click at ${e.clientX},${e.clientY}\n`);
    let result = { x: e.clientX, y: e.clientY };
    FissionTestHelper.fireEventInEmbedder("OOPIF:ClickData", result);
  });
  dump("OOPIF registered click listener\n");
  return true;
};

async function clickOnIframe(x, y) {
  let iframePromise = promiseOneEvent(window, "OOPIF:ClickData", null);
  await synthesizeNativeMouseEventWithAPZ(
    { type: "click", target: document.body, offsetX: x, offsetY: y },
    () => dump("Finished synthesizing click, waiting for OOPIF message...\n")
  );
  let iframeResponse = await iframePromise;
  dump("OOPIF response: " + JSON.stringify(iframeResponse.data) + "\n");
  return iframeResponse.data;
}

let oopif_scroll_pos = function() {
  dump(`OOPIF scroll position is y=${window.scrollY}\n`);
  let result = { y: window.scrollY };
  FissionTestHelper.fireEventInEmbedder("OOPIF:ScrollPos", result);
  return true;
};

async function getIframeScrollY() {
  let iframeElement = document.getElementById("testframe");
  let iframePromise = promiseOneEvent(window, "OOPIF:ScrollPos", null);
  ok(await FissionTestHelper.sendToOopif(iframeElement, `(${oopif_scroll_pos})()`), "Sent scrollY request");
  let iframeResponse = await iframePromise;
  dump("OOPIF response for scrollPos: " + JSON.stringify(iframeResponse.data) + "\n");
  return iframeResponse.data.y;
}

let make_oopif_scrollable = function() {
  // ensure the oopif is scrollable, and wait for the paint so that the
  // compositor also knows it's scrollable.
  document.body.style.height = "200vh";
  promiseApzFlushedRepaints().then(() => {
    let result = { y: window.scrollMaxY };
    FissionTestHelper.fireEventInEmbedder("OOPIF:Scrollable", result);
  });
  // Also register a scroll listener for when it actually gets scrolled.
  window.addEventListener("scroll", function(e) {
    dump(`OOPIF got scroll event, now at ${window.scrollY}\n`);
    let result = { y: window.scrollY };
    FissionTestHelper.fireEventInEmbedder("OOPIF:Scrolled", result);
  }, {once: true});
  return true;
};

function failsafe(eventType) {
  // Catch and fail faster on the case where the event ends up not going to
  // the iframe like it should. Otherwise the test hangs until timeout which
  // is more painful.
  document.addEventListener(eventType, function(e) {
    dump(`${location.href} got ${e.type} at ${e.clientX},${e.clientY}\n`);
    ok(false, `The OOPIF hosting page should not have gotten the ${eventType}`);
    setTimeout(FissionTestHelper.subtestFailed, 0);
  }, {once: true});
}

// The actual test

async function test() {
  ok(SpecialPowers.getBoolPref("apz.paint_skipping.enabled"),
     "paint-skipping is expected to be enabled for this test to be meaningful");

  let iframeElement = document.getElementById("testframe");

  let iframeResponse = await FissionTestHelper.sendToOopif(iframeElement, `(${code_for_oopif_to_run})()`);
  dump("OOPIF response: " + JSON.stringify(iframeResponse) + "\n");
  ok(iframeResponse, "code_for_oopif_to_run successfully installed");

  is(window.scrollY, 0, "window is at 0 scroll position");

  // hit-test into the iframe before scrolling
  let oldClickPoint = await clickOnIframe(50, 250);

  // do an APZ scroll and wait for the main-thread to get the repaint request,
  // and queue up a paint-skip scroll notification back to APZ.
  await promiseMoveMouseAndScrollWheelOver(document.body, 10, 10);

  // The wheel scroll might have started an APZ animation, so run that to the end
  var utils = SpecialPowers.getDOMWindowUtils(window);
  for (var i = 0; i < 60; i++) {
    utils.advanceTimeAndRefresh(16);
  }
  utils.restoreNormalRefresh();
  // Let the repaint requests get processed
  await promiseOnlyApzControllerFlushed();
  await promiseAllPaintsDone();

  ok(window.scrollY > 5, "window has scrolled by " + window.scrollY + " pixels");

  // hit-test into the iframe after scrolling. The coordinates here are the
  // same relative to the body as before, but get computed to be different
  // relative to the window/screen.
  let newClickPoint = await clickOnIframe(50, 250);

  is(newClickPoint.x, oldClickPoint.x, "x-coord of old and new match");
  is(newClickPoint.y, oldClickPoint.y, "y-coord of old and new match");

  // Also check that we can send scroll events to the OOPIF. Any wheel events
  // delivered to this page after this point should result in a failure.
  failsafe("wheel");

  let iframeY = await getIframeScrollY();
  is(iframeY, 0, "scrollY of iframe should be 0 initially");

  // Ensure the OOPIF is scrollable.
  let scrollablePromise = promiseOneEvent(window, "OOPIF:Scrollable", null);
  ok(await FissionTestHelper.sendToOopif(iframeElement, `(${make_oopif_scrollable})()`), "Made OOPIF scrollable");
  let oopifScrollMaxY = (await scrollablePromise).data.y;
  ok(oopifScrollMaxY > 0, "Confirmed that oopif is scrollable");

  // Now scroll over the OOP-iframe (we know it must be under the 50,250 point
  // because we just checked that above). Note that listening for wheel/scroll
  // events is trickier because they will fire in the OOPIF, so we can't just
  // use promiseMoveMouseAndScrollWheelOver directly.
  let scrolledPromise = promiseOneEvent(window, "OOPIF:Scrolled", null);
  await synthesizeNativeWheel(document.body, 50, 250, 0, -10);
  iframeY = (await scrolledPromise).data.y;
  ok(iframeY > 0, "scrollY of iframe should be >0 after scrolling");
}

  </script>
</head>
<body onload="failsafe('click')">
<iframe style="margin-top: 200px" id="testframe"></iframe>
<div style="height: 5000px">tall div to make the page scrollable</div>
</body>
</html>