summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/test/mochitest/helper_visual_scrollbars_pagescroll.html
blob: ae3025930fb6242addb1f887a27bda2a92fcb94f (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
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Clicking on the scrollbar track in quick succession should scroll the right amount</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 src="/tests/SimpleTest/EventUtils.js"></script>

  <script type="application/javascript">

// A helper to synthesize a native mouse click on a scrollbar track,
// and wait long enough such that subsequent ticking of the refresh
// driver will progress any resulting scroll animation.
// In particular, just `await promiseNativeMouseEventWithApz(...)`
// is not enough, it waits for the synthesization messages to arrive
// in the parent process, but the native events may still be in the
// OS event queue. Instead, we need to wait for a synthesized event
// to arrive at content. While we're synthesizing a "click", if the
// target is a scrollbar the window only gets the "mousedown" and
// "mouseup", not a "click". Waiting for the "mousedown" is not enough
// (the "mouseup" can still be stuck in the event queue), so we wait
// for "mouseup".
async function promiseNativeMouseClickOnScrollbarTrack(anchor, xOffset, yOffset) {
  await promiseNativeMouseEventWithAPZAndWaitForEvent({
    type: "click",
    target: anchor,
    offsetX: xOffset,
    offsetY: yOffset,
    eventTypeToWait: "mouseup"
  });
}

async function test() {
  var scroller = document.documentElement;
  var verticalScrollbarWidth = window.innerWidth - scroller.clientWidth;

  if (verticalScrollbarWidth == 0) {
    ok(true, "Scrollbar width is zero on this platform, test is useless here");
    return;
  }

  // The anchor is the fixed-pos div that we use to calculate coordinates to
  // click on the scrollbar. That way we don't have to recompute coordinates
  // as the page scrolls. The anchor is at the bottom-right corner of the
  // content area.
  var anchor = document.getElementById('anchor');

  var xoffset = (verticalScrollbarWidth / 2);
  // Get a y-coord near the bottom of the vertical scrollbar track. Assume the
  // vertical thumb is near the top of the scrollback track (since scroll
  // position starts off at zero) and won't get in the way. Also assume the
  // down arrow button, if there is one, is square.
  var yoffset = 0 - verticalScrollbarWidth - 5;

  // Take control of the refresh driver
  let utils = SpecialPowers.getDOMWindowUtils(window);
  utils.advanceTimeAndRefresh(0);

  // Click at the bottom of the scrollbar track to trigger a page-down kind of
  // scroll. This should use "desktop zooming" scrollbar code which should
  // trigger an APZ scroll animation.
  await promiseNativeMouseClickOnScrollbarTrack(anchor, xoffset, yoffset);

  // Run 1000 frames, that should be enough to let the scroll animation start
  // and run to completion. We check that it scrolled at least half the visible
  // height, since we expect about a full screen height minus a few lines.
  for (let i = 0; i < 1000; i++) {
    utils.advanceTimeAndRefresh(16);
  }
  await promiseOnlyApzControllerFlushed();

  let pageScrollAmount = scroller.scrollTop;
  ok(pageScrollAmount > scroller.clientHeight / 2,
     `Scroll offset is ${pageScrollAmount}, should be near clientHeight ${scroller.clientHeight}`);

  // Now we do two clicks in quick succession, but with a few frames in between
  // to verify the scroll animation from the first click is active before the
  // second click happens.
  await promiseNativeMouseClickOnScrollbarTrack(anchor, xoffset, yoffset);
  for (let i = 0; i < 5; i++) {
    utils.advanceTimeAndRefresh(16);
  }
  await promiseOnlyApzControllerFlushed();
  let curPos = scroller.scrollTop;
  ok(curPos > pageScrollAmount, `Scroll offset has increased to ${curPos}`);
  ok(curPos < pageScrollAmount * 2, "Second page-scroll is not yet complete");
  await promiseNativeMouseClickOnScrollbarTrack(anchor, xoffset, yoffset);

  // Run to completion and check that we are around 3x pageScrollAmount, with
  // some allowance for fractional rounding.
  for (let i = 0; i < 1000; i++) {
    utils.advanceTimeAndRefresh(16);
  }
  await promiseOnlyApzControllerFlushed();
  curPos = scroller.scrollTop;
  ok(Math.abs(curPos - (pageScrollAmount * 3)) < 3,
     `Final scroll offset ${curPos} is close to 3x${pageScrollAmount}`);

  utils.restoreNormalRefresh();
}

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

  </script>
</head>
<body>
 <div style="position:fixed; bottom: 0; right: 0; width: 1px; height: 1px" id="anchor"></div>
 <div style="height: 300vh; margin-bottom: 10000px; background-image: linear-gradient(red,blue)"></div>
  The above div is sized to 3x screen height so the linear gradient is more steep in terms of
  color/pixel. We only scroll a few pages worth so we don't need the gradient all the way down.
  And then we use a bottom-margin to make the page really big so the scrollthumb is
  relatively small, giving us lots of space to click on the scrolltrack.
</body>
</html>