bug970964_inner2.html (13011B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 https://bugzilla.mozilla.org/show_bug.cgi?id=970964 5 --> 6 <head> 7 <title>Test for Bug 970964</title> 8 <script src="/tests/SimpleTest/SimpleTest.js"></script> 9 <script src="/tests/SimpleTest/EventUtils.js"></script> 10 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 11 </head> 12 <body> 13 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=970964">Mozilla Bug 970964</a> 14 <p id="display"></p> 15 <div id="content" style="display: none"> 16 17 </div> 18 <pre id="test"> 19 <script type="application/javascript"> 20 21 /** Test for Bug 970964 */ 22 23 function ok(condition, msg) { 24 parent.ok(condition, msg); 25 } 26 27 function is(a, b, msg) { 28 parent.is(a, b, msg); 29 } 30 31 function testtouch(aOptions) { 32 if (!aOptions) 33 aOptions = {}; 34 this.identifier = aOptions.identifier || 0; 35 this.target = aOptions.target || 0; 36 this.page = aOptions.page || {x: 0, y: 0}; 37 this.radius = aOptions.radius || {x: 0, y: 0}; 38 this.rotationAngle = aOptions.rotationAngle || 0; 39 this.force = aOptions.force || 1; 40 } 41 42 function touchEvent(aOptions) { 43 if (!aOptions) { 44 aOptions = {}; 45 } 46 this.ctrlKey = aOptions.ctrlKey || false; 47 this.altKey = aOptions.altKey || false; 48 this.shiftKey = aOptions.shiftKey || false; 49 this.metaKey = aOptions.metaKey || false; 50 this.touches = aOptions.touches || []; 51 this.targetTouches = aOptions.targetTouches || []; 52 this.changedTouches = aOptions.changedTouches || []; 53 } 54 55 function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) { 56 var ids = [], xs=[], ys=[], rxs = [], rys = [], 57 rotations = [], forces = [], tiltXs = [], tiltYs = [], twists = []; 58 59 for (var touchType of ["touches", "changedTouches", "targetTouches"]) { 60 for (var i = 0; i < aEvent[touchType].length; i++) { 61 if (!ids.includes(aEvent[touchType][i].identifier)) { 62 ids.push(aEvent[touchType][i].identifier); 63 xs.push(aEvent[touchType][i].page.x); 64 ys.push(aEvent[touchType][i].page.y); 65 rxs.push(aEvent[touchType][i].radius.x); 66 rys.push(aEvent[touchType][i].radius.y); 67 rotations.push(aEvent[touchType][i].rotationAngle); 68 forces.push(aEvent[touchType][i].force); 69 tiltXs.push(0); 70 tiltYs.push(0); 71 twists.push(0); 72 } 73 } 74 } 75 return windowUtils.sendTouchEvent(aType, 76 ids, xs, ys, rxs, rys, 77 rotations, forces, tiltXs, tiltYs, twists, 78 aModifiers); 79 } 80 81 function getDefaultArgEvent(eventname) { 82 return new PointerEvent(eventname, { 83 bubbles: true, cancelable: true, view: window, 84 detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0, 85 ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, 86 button: 0, relatedTarget: null, pointerId: 0 87 }); 88 } 89 90 function getTouchEventForTarget(target, cwu, id) { 91 var bcr = target.getBoundingClientRect(); 92 var touch = new testtouch({ 93 page: {x: Math.round(bcr.left + bcr.width/2), 94 y: Math.round(bcr.top + bcr.height/2)}, 95 target: target, 96 identifier: id, 97 }); 98 var event = new touchEvent({ 99 touches: [touch], 100 targetTouches: [touch], 101 changedTouches: [touch] 102 }); 103 return event; 104 } 105 106 function runTests() { 107 var d0 = document.getElementById("d0"); 108 var d1 = document.getElementById("d1"); 109 var d2 = document.getElementById("d2"); 110 var d3 = document.getElementById("d3"); 111 112 // Test Pointer firing before any mouse/touch original source 113 114 var mouseDownTriggered = 0; 115 var pointerDownTriggered = 0; 116 var touchDownTriggered = 0; 117 var touchCancelTriggered = 0; 118 var pointerCancelTriggered = 0; 119 120 // Test pointer event generated from mouse event 121 d0.addEventListener("mousedown", (e) => { 122 ++mouseDownTriggered; 123 is(pointerDownTriggered , mouseDownTriggered, "Mouse event must be triggered after pointer event!"); 124 }, {once: true}); 125 126 d0.addEventListener("pointerdown", (e) => { 127 ++pointerDownTriggered; 128 is(pointerDownTriggered, mouseDownTriggered + 1, "Pointer event must be triggered before mouse event!"); 129 }, {once: true}); 130 131 synthesizeMouse(d1, 3, 3, { type: "mousemove"}); 132 synthesizeMouse(d1, 3, 3, { type: "mousedown"}); 133 synthesizeMouse(d1, 3, 3, { type: "mouseup"}); 134 135 // Test pointer event generated from touch event 136 mouseDownTriggered = 0; 137 pointerDownTriggered = 0; 138 139 d0.addEventListener("touchstart", (e) => { 140 ++touchDownTriggered; 141 is(pointerDownTriggered, touchDownTriggered, "Touch event must be triggered after pointer event!"); 142 }, {once: true}); 143 144 d0.addEventListener("mousedown", (e) => { 145 ++mouseDownTriggered; 146 is(pointerDownTriggered , mouseDownTriggered, "Mouse event must be triggered after pointer event!"); 147 }, {once: true}); 148 149 d0.addEventListener("pointerdown", (e) => { 150 ++pointerDownTriggered; 151 is(pointerDownTriggered, touchDownTriggered + 1, "Pointer event must be triggered before mouse event!"); 152 is(pointerDownTriggered, mouseDownTriggered + 1, "Pointer event must be triggered before mouse event!"); 153 }, {once: true}); 154 155 d0.addEventListener("touchcancel", (e) => { 156 ++touchCancelTriggered; 157 is(pointerCancelTriggered, touchCancelTriggered, "Touch cancel event must be triggered after pointer event!"); 158 }, {once: true}); 159 160 d0.addEventListener("pointercancel", function(ev) { 161 is(ev.pointerId, 0, "Correct default pointerId"); 162 is(ev.bubbles, true, "bubbles should be true"); 163 is(ev.cancelable, false, "pointercancel cancelable should be false "); 164 ++pointerCancelTriggered; 165 is(pointerCancelTriggered, touchCancelTriggered + 1, "Pointer event must be triggered before touch event!"); 166 }, {once: true}); 167 168 var cwu = SpecialPowers.getDOMWindowUtils(window); 169 var event1 = getTouchEventForTarget(d1, cwu, 0); 170 sendTouchEvent(cwu, "touchstart", event1, 0); 171 sendTouchEvent(cwu, "touchmove", event1, 0); 172 // Test Touch to Pointer Cancel 173 sendTouchEvent(cwu, "touchcancel", event1, 0); 174 175 // Check Pointer enter/leave from mouse generated event 176 var mouseEnterTriggered = 0; 177 var pointerEnterTriggered = 0; 178 d2.onpointerenter = function(e) { 179 pointerEnterTriggered = 1; 180 is(e.bubbles, false, "bubbles should be false"); 181 is(e.cancelable, false, "cancelable should be false"); 182 is(mouseEnterTriggered, 0, "Pointer event must be triggered before mouse event!"); 183 }; 184 d2.onmouseenter = function(e) { 185 mouseEnterTriggered = 1; 186 is(pointerEnterTriggered , 1, "Mouse event must be triggered after pointer event!"); 187 }; 188 synthesizeMouse(d2, 3, 3, { type: "mousemove"}); 189 d2.onmouseenter = function(e) {} 190 191 // Test Multi Pointer enter/leave for pointers generated from Mouse and Touch at the same time 192 // Enter mouse and touch generated pointers to different elements 193 var d1enterCount = 0; 194 var d2enterCount = 0; 195 var d3enterCount = 0; 196 var d1leaveCount = 0; 197 var d2leaveCount = 0; 198 var d3leaveCount = 0; 199 var mousePointerEnterLeaveCount = 0; 200 var touchPointerEnterLeaveCount = 0; 201 202 var checkPointerType = function(pointerType) { 203 if (pointerType == "mouse") { 204 ++mousePointerEnterLeaveCount; 205 } else if (pointerType == "touch") { 206 ++touchPointerEnterLeaveCount; 207 } 208 }; 209 210 d1.onpointerenter = function(e) { 211 ++d1enterCount; 212 is(e.bubbles, false, "bubbles should be false"); 213 is(e.cancelable, false, "cancelable should be false"); 214 checkPointerType(e.pointerType); 215 }; 216 d2.onpointerenter = function(e) { 217 ++d2enterCount; 218 is(e.bubbles, false, "bubbles should be false"); 219 is(e.cancelable, false, "cancelable should be false"); 220 checkPointerType(e.pointerType); 221 }; 222 d3.onpointerenter = function(e) { 223 ++d3enterCount; 224 is(e.bubbles, false, "bubbles should be false"); 225 is(e.cancelable, false, "cancelable should be false"); 226 checkPointerType(e.pointerType); 227 }; 228 d1.onpointerleave = function(e) { 229 ++d1leaveCount; 230 is(e.bubbles, false, "bubbles should be false"); 231 is(e.cancelable, false, "cancelable should be false"); 232 checkPointerType(e.pointerType); 233 }; 234 d2.onpointerleave = function(e) { 235 ++d2leaveCount; 236 is(e.bubbles, false, "bubbles should be false"); 237 is(e.cancelable, false, "cancelable should be false"); 238 checkPointerType(e.pointerType); 239 }; 240 d3.onpointerleave = function(e) { 241 ++d3leaveCount; 242 is(e.bubbles, false, "bubbles should be false"); 243 is(e.cancelable, false, "cancelable should be false"); 244 checkPointerType(e.pointerType); 245 }; 246 247 synthesizeMouse(d1, 3, 3, { type: "mousemove"}); 248 sendTouchEvent(cwu, "touchstart", getTouchEventForTarget(d3, cwu, 3), 0); 249 sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d3, cwu, 3), 0); 250 is(touchPointerEnterLeaveCount, 1, "Wrong touch enterLeave count for!"); 251 is(mousePointerEnterLeaveCount, 2, "Wrong mouse enterLeave count for!"); 252 253 is(d1enterCount, 1, "Wrong enter count for! d1"); 254 is(d2leaveCount, 1, "Wrong leave count for! d2"); 255 is(d3enterCount, 1, "Wrong enter count for! d3"); 256 257 sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d1, cwu, 3), 0); 258 synthesizeMouse(d3, 3, 3, { type: "mousemove"}); 259 is(touchPointerEnterLeaveCount, 1, "Wrong touch enterLeave count for!"); 260 is(mousePointerEnterLeaveCount, 4, "Wrong mouse enterLeave count for!"); 261 262 is(d3leaveCount, 0, "Wrong leave count for! d3"); 263 is(d1leaveCount, 1, "Wrong leave count for! d1"); 264 is(d1enterCount, 1, "Wrong enter count for! d1"); 265 is(d3enterCount, 2, "Wrong enter count for! d3"); 266 267 sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d2, cwu, 3), 0); 268 synthesizeMouse(d2, 3, 3, { type: "mousemove"}); 269 is(touchPointerEnterLeaveCount, 1, "Wrong touch enterLeave count for!"); 270 is(mousePointerEnterLeaveCount, 6, "Wrong mouse enterLeave count for!"); 271 272 is(d1leaveCount, 1, "Wrong leave count for! d1"); 273 is(d2enterCount, 1, "Wrong enter count for! d2"); 274 is(d3leaveCount, 1, "Wrong leave count for! d3"); 275 276 sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d1, cwu, 3), 0); 277 synthesizeMouse(d1, 3, 3, { type: "mousemove"}); 278 is(touchPointerEnterLeaveCount, 1, "Wrong touch enterLeave count for!"); 279 is(mousePointerEnterLeaveCount, 8, "Wrong mouse enterLeave count for!"); 280 281 is(d2leaveCount, 2, "Wrong leave count for! d2"); 282 is(d1enterCount, 2, "Wrong enter count for! d1"); 283 284 // Test for pointer buttons when it generated from mousemove event 285 d1.onpointermove = function(e) { 286 is(e.buttons, 0, "Buttons must be 0 on pointer generated from mousemove"); 287 is(e.button, -1, "Button must be -1 on pointer generated from mousemove when no buttons pressed"); 288 is(e.pointerType, "mouse", "Pointer type must be mouse"); 289 }; 290 synthesizeMouseAtPoint(4, 4, { type: "mousemove" }); 291 292 d1.onpointermove = function(e) { 293 is(e.buttons, 1, "Buttons must be 1 on pointermove generated from touch event"); 294 is(e.button, -1, "Button must be -1 on pointermove generated from touch event"); 295 is(e.pointerType, "touch", "Pointer type must be touch"); 296 }; 297 sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d1, cwu, 2), 0); 298 299 // Test for cancel trigger pointerOut (Touch Pointer must be at d1 now) 300 pointerCancelTriggered = 0; 301 var pointerOutTriggeredForCancelEvent = 0; 302 var pointerLeaveTriggeredForCancelEvent = 0; 303 d3.onpointerout = function(e) { 304 if (pointerOutTriggeredForCancelEvent == 0) { 305 is(e.pointerId, 3, "Wrong Pointer type, should be id from Touch event"); 306 is(e.pointerType, "touch", "Wrong Pointer type, should be touch type"); 307 } else { 308 is(e.pointerId, 0, "Wrong Pointer type, should be id from mouse event"); 309 is(e.pointerType, "mouse", "Wrong Pointer type, should be mouse type"); 310 } 311 pointerOutTriggeredForCancelEvent = 1; 312 }; 313 d3.onpointerleave = function(e) { 314 is(pointerOutTriggeredForCancelEvent, 1, "Pointer Out must be dispatched bedore Pointer leave"); 315 if (pointerLeaveTriggeredForCancelEvent == 0) { 316 is(e.pointerId, 3, "Wrong Pointer type, should be id from Touch event"); 317 is(e.pointerType, "touch", "Wrong Pointer type, should be touch type"); 318 } else { 319 is(e.pointerId, 0, "Wrong Pointer type, should be id from mouse event"); 320 is(e.pointerType, "mouse", "Wrong Pointer type, should be mouse type"); 321 } 322 pointerLeaveTriggeredForCancelEvent = 1; 323 } 324 sendTouchEvent(cwu, "touchcancel", getTouchEventForTarget(d1, cwu, 3), 0); 325 is(pointerOutTriggeredForCancelEvent, 1, "Pointer Out not dispatched on PointerCancel"); 326 is(pointerLeaveTriggeredForCancelEvent, 1, "Pointer Leave not dispatched on PointerCancel"); 327 328 finishTest(); 329 } 330 331 function finishTest() { 332 // Let window.onerror have a chance to fire 333 setTimeout(function() { 334 setTimeout(function() { 335 window.parent.postMessage("finishTest", "*"); 336 }, 0); 337 }, 0); 338 } 339 340 window.onload = function () { 341 SpecialPowers.pushPrefEnv({ 342 "set": [ 343 ["dom.w3c_pointer_events.implicit_capture", true] 344 ] 345 }, runTests); 346 } 347 348 </script> 349 </pre> 350 <div id="d0"> 351 Test divs -- 352 <div id="d1">t</div><div id="d2">t</div><div id="d3">t</div> 353 -- 354 </div> 355 </body> 356 </html>