summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/test/mochitest/helper_long_tap.html
blob: 2fdb2472ecf73761dc1bc580625515fa26152985 (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
159
160
161
162
163
164
165
166
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width; initial-scale=1.0">
  <title>Ensure we get a touch-cancel after a contextmenu comes up</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 type="application/javascript">

function addMouseEventListeners(aTarget) {
  aTarget.addEventListener("mousemove", recordEvent, true);
  aTarget.addEventListener("mouseover", recordEvent, true);
  aTarget.addEventListener("mouseenter", recordEvent, true);
  aTarget.addEventListener("mouseout", recordEvent, true);
  aTarget.addEventListener("mouseleave", recordEvent, true);
}

function removeMouseEventListeners(aTarget) {
  aTarget.removeEventListener("mousemove", recordEvent, true);
  aTarget.removeEventListener("mouseover", recordEvent, true);
  aTarget.removeEventListener("mouseenter", recordEvent, true);
  aTarget.removeEventListener("mouseout", recordEvent, true);
  aTarget.removeEventListener("mouseleave", recordEvent, true);
}

async function longPressLink() {
  let target = document.getElementById("b");
  addMouseEventListeners(target);
  await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, function() {
    dump("Finished synthesizing touch-start, waiting for events...\n");
  });
}

var eventsFired = 0;
function recordEvent(e) {
  let target = document.getElementById("b");
  const platform = getPlatform();
  if (platform == "windows") {
    // On Windows we get a mouselongtap event once the long-tap has been detected
    // by APZ, and that's what we use as the trigger to lift the finger. That then
    // triggers the contextmenu. This matches the platform convention.
    switch (eventsFired) {
      case 0: is(e.type, "touchstart", "Got a touchstart"); break;
      case 1:
        is(e.type, "mouselongtap", "Got a mouselongtap");
        setTimeout(async () => {
          await synthesizeNativeTouch(document.getElementById("b"), 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE);
        }, 0);
        break;
      case 2: is(e.type, "touchend", "Got a touchend"); break;
      case 3: is(e.type, "mouseover", "Got a mouseover"); break;
      case 4: is(e.type, "mouseenter", "Got a mouseenter"); break;
      case 5: is(e.type, "mousemove", "Got a mousemove"); break;
      case 6: is(e.type, "contextmenu", "Got a contextmenu"); e.preventDefault(); break;
      default: ok(false, "Got an unexpected event of type " + e.type); break;
    }
    eventsFired++;

    if (eventsFired == 7) {
      removeMouseEventListeners(target);
      dump("Finished waiting for events, doing an APZ flush to see if any more unexpected events come through...\n");
      promiseOnlyApzControllerFlushed().then(function() {
        dump("Done APZ flush, ending test...\n");
        subtestDone();
      });
    }
  } else if (platform != "android") {
    // On non-Windows desktop platforms we get a contextmenu event once the
    // long-tap has been detected. Since we prevent-default that, we don't get
    // a mouselongtap event at all, and instead get a touchcancel.
    switch (eventsFired) {
      case 0: is(e.type, "touchstart", "Got a touchstart"); break;
      case 1: is(e.type, "mouseover", "Got a mouseover"); break;
      case 2: is(e.type, "mouseenter", "Got a mouseenter"); break;
      case 3: is(e.type, "mousemove", "Got a mousemove"); break;
      case 4: is(e.type, "contextmenu", "Got a contextmenu"); e.preventDefault(); break;
      case 5: is(e.type, "touchcancel", "Got a touchcancel"); break;
      default: ok(false, "Got an unexpected event of type " + e.type); break;
    }
    eventsFired++;

    if (eventsFired == 6) {
      removeMouseEventListeners(target);
      setTimeout(async () => {
        await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, function() {
          dump("Finished synthesizing touch-end, doing an APZ flush to see if any more unexpected events come through...\n");
          promiseOnlyApzControllerFlushed().then(function() {
            dump("Done APZ flush, ending test...\n");
            subtestDone();
          });
        });
      }, 0)
    }
  } else {
    // On Android we get a contextmenu event once the long-tap has been
    // detected. If contextmenu opens we get a touchcancel event, and if
    // contextmenu didn't open because of preventDefault() in the content,
    // we will not get the touchcancel event.
    switch (eventsFired) {
      case 0: is(e.type, "touchstart", "Got a touchstart"); break;
      case 1: is(e.type, "mouseover", "Got a mouseover"); break;
      case 2: is(e.type, "mouseenter", "Got a mouseenter"); break;
      case 3: is(e.type, "mousemove", "Got a mousemove"); break;
      case 4: is(e.type, "contextmenu", "Got a contextmenu");
        // Do preventDefault() in this content, thus we will not get any
        // touchcancel event.
        e.preventDefault();
        setTimeout(async () => {
          await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, function() {
            dump("Finished synthesizing touch-end, waiting for a touchend event...\n");
          });
        }, 0);
        break;
      case 5: is(e.type, "touchend", "Got a touchend");
        // Send another long press.
        setTimeout(async () => {
          await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, function() {
            dump("Finished synthesizing touch-start, waiting for events...\n");
          });
        }, 0);
        break;
      case 6: is(e.type, "touchstart", "Got another touchstart"); break;
      // NOTE: In this another event case, we don't get mouseover or moveenter
      // event either since the target element hasn't been changed.
      case 7: is(e.type, "mousemove", "Got another mousemove"); break;
      case 8: is(e.type, "contextmenu", "Got another contextmenu");
        // DON'T DO preventDefault() this time, thus we should get a touchcancel
        // event.
        break;
      case 9: is(e.type, "touchcancel", "Got a touchcancel"); break;
      default: ok(false, "Got an unexpected event of type " + e.type); break;
    }
    eventsFired++;

    if (eventsFired == 10) {
      removeMouseEventListeners(target);
      setTimeout(async () => {
        await synthesizeNativeTouch(target, 5, 5, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, function() {
          dump("Finished synthesizing touch-end, doing an APZ flush to see if any more unexpected events come through...\n");
          promiseOnlyApzControllerFlushed().then(function() {
            dump("Done APZ flush, ending test...\n");
            subtestDone();
          });
        });
      }, 0);
    }
  }
}

window.addEventListener("touchstart", recordEvent, { passive: true, capture: true });
window.addEventListener("touchend", recordEvent, { passive: true, capture: true });
window.addEventListener("touchcancel", recordEvent, true);
window.addEventListener("contextmenu", recordEvent, true);
SpecialPowers.addChromeEventListener("mouselongtap", recordEvent, true);

waitUntilApzStable()
.then(longPressLink);

  </script>
</head>
<body>
 <a id="b" href="#">Link to nowhere</a>
</body>
</html>