summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/test/mochitest/helper_scrollbar_snap_bug1501062.html
blob: ec18fd856d52a1ec32c049462fbf67edeb8c8171 (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
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width; initial-scale=1.0">
  <title>Exercising the slider.snapMultiplier code</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>
</head>
<body>
  <div id="scrollable" style="width: 300px; height: 300px; overflow: auto">
    <div id="filler" style="height: 2000px; background-image: linear-gradient(red,blue)"></div>
  </div>
</body>
<script type="text/javascript">
async function test() {
  // Note that this pref is a read-once-on-startup pref so we can't change it
  // and have the change take effect. Instead we just use the value to determine
  // what the expected behaviour is.
  var snapMultiplier = SpecialPowers.getIntPref("slider.snapMultiplier");

  // Much of the code below is "inlined" from promiseVerticalScrollbarDrag. Reusing
  // that code was nontrivial given the modifications we needed to make, and
  // would have increased the complexity of that helper function more than I'd
  // like. However if any bugfixes are made to that function this code might
  // need to be updated as well.

  var scrollableDiv = document.getElementById("scrollable");
  var boundingClientRect = scrollableDiv.getBoundingClientRect();
  var verticalScrollbarWidth = boundingClientRect.width - scrollableDiv.clientWidth;
  if (verticalScrollbarWidth == 0) {
    ok(true, "No scrollbar, can't do this test");
    return;
  }

  // register a scroll listener for the initial drag
  let scrollPromise = new Promise(resolve => {
    scrollableDiv.addEventListener("scroll", resolve, {once: true});
  });

  var upArrowHeight = verticalScrollbarWidth; // assume square scrollbar buttons
  var mouseX = scrollableDiv.clientWidth + (verticalScrollbarWidth / 2);
  var mouseY = upArrowHeight + 5; // start dragging somewhere in the thumb

  dump("Starting drag at " + mouseX + ", " + mouseY + " from top-left of #" + scrollableDiv.id + "\n");

  // Move the mouse to the scrollbar thumb and drag it down
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousedown",
  });
  // drag down by 100 pixels
  mouseY += 100;
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });

  // wait here until the scroll event listener is triggered.
  await scrollPromise;
  var savedScrollPos = scrollableDiv.scrollTop;
  ok(savedScrollPos > 0, "Scrolled to " + savedScrollPos);

  // register a new scroll event listener. The next mousemove below will either
  // trigger the snapback behaviour (if snapMultiplier > 0) or trigger a vertical
  // scroll (if snapMultiplier == 0) because of the x- and y-coordinates we move
  // the mouse to. This allows us to wait for a scroll event in either case.
  // If we only triggered the snapback case then waiting for the scroll to
  // "not happen" in the other case would be more error-prone.
  scrollPromise = new Promise(resolve => {
    scrollableDiv.addEventListener("scroll", resolve, {once: true});
  });
  // Add 2 to snapMultipler just to make sure we get far enough away from the scrollbar
  var snapBackDistance = (snapMultiplier + 2) * verticalScrollbarWidth;
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX + snapBackDistance,
    offsetY: mouseY + 10,
    type: "mousemove",
  });

  // wait here until the scroll happens
  await scrollPromise;
  if (snapMultiplier > 0) {
    ok(scrollableDiv.scrollTop == 0, "Scroll position snapped back to " + scrollableDiv.scrollTop);
  } else {
    ok(scrollableDiv.scrollTop > savedScrollPos, "Scroll position increased to " + scrollableDiv.scrollTop);
  }

  // Now we move the mouse back to the old position to ensure the scroll position
  // gets restored properly
  scrollPromise = new Promise(resolve => {
    scrollableDiv.addEventListener("scroll", resolve, {once: true});
  });
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });

  // wait here until the scroll happens
  await scrollPromise;
  ok(scrollableDiv.scrollTop == savedScrollPos, "Scroll position was restored to " + scrollableDiv.scrollTop);

  // Release mouse and ensure the scroll position stuck
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mouseup",
  });
  // Flush everything just to be safe
  await promiseOnlyApzControllerFlushed();

  ok(scrollableDiv.scrollTop == savedScrollPos, "Final scroll position was " + scrollableDiv.scrollTop);
}

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

</script>
</html>