test_pointer_event.html (10359B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 https://bugzilla.mozilla.org/show_bug.cgi?id=1363508 5 --> 6 <head> 7 <meta charset="utf-8"> 8 <title>Test for Pointer Events spoofing</title> 9 <script src="/tests/SimpleTest/SimpleTest.js"></script> 10 <script src="/tests/SimpleTest/EventUtils.js"></script> 11 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 12 </head> 13 <body> 14 <div id="target0" style="width: 50px; height: 50px; background: green"></div> 15 <div id="target1" style="width: 50px; height: 50px; background: black"></div> 16 <script type="application/javascript"> 17 /** Test for Bug 1363508 */ 18 SimpleTest.waitForExplicitFinish(); 19 20 const { AppConstants } = SpecialPowers.ChromeUtils.importESModule( 21 "resource://gre/modules/AppConstants.sys.mjs" 22 ); 23 24 var target0 = window.document.getElementById("target0"); 25 var target1 = window.document.getElementById("target1"); 26 var utils = SpecialPowers.Ci.nsIDOMWindowUtils; 27 28 // A helper function to check that whether the pointer is spoofed correctly. 29 function checkPointerEvent(aEvent) { 30 is(aEvent.width, 1, "The spoofed pointer event should always have width as 1."); 31 is(aEvent.height, 1, "The spoofed pointer event should always have width as 1."); 32 if (aEvent.buttons === 0) { 33 is(aEvent.pressure, 0.0, 34 "The spoofed pointer event should have pressure as 0.0 if it is not in a active buttons state."); 35 } else { 36 is(aEvent.pressure, 0.5, 37 "The spoofed pointer event should have pressure as 0.5 if it is in a active buttons state."); 38 } 39 is(aEvent.tangentialPressure, 0, "The spoofed pointer event should always have tangentialPressure as 0."); 40 is(aEvent.tiltX, 0, "The spoofed pointer event should always have tiltX as 0."); 41 is(aEvent.tiltY, 0, "The spoofed pointer event should always have tiltY as 0."); 42 is(aEvent.twist, 0, "The spoofed pointer event should always have twist as 0."); 43 if (AppConstants.platform == "macosx") { 44 is(aEvent.pointerId, utils.DEFAULT_MOUSE_POINTER_ID, 45 "The spoofed pointer event should always have the mouse pointer id."); 46 is(aEvent.pointerType, "mouse", "The spoofed pointer event should always has mouse pointerType."); 47 is(aEvent.isPrimary, true, "The spoofed pointer event should only receive primary pointer events."); 48 } 49 } 50 51 // A helper function to create a promise for waiting the event. 52 function promiseForEvent(aEventType, aCheckFunc) { 53 return new Promise(resolve => { 54 target0.addEventListener(aEventType, (event) => { 55 is(event.type, aEventType, "receive " + event.type + " on target0"); 56 aCheckFunc(event); 57 resolve(); 58 }, { once: true }); 59 }); 60 } 61 62 // A test for pointer events from touch interface. 63 async function doTestForTouchPointerEvent() { 64 let eventPromises = [ 65 promiseForEvent("pointerover", checkPointerEvent), 66 promiseForEvent("pointerenter", checkPointerEvent), 67 promiseForEvent("pointerdown", checkPointerEvent), 68 promiseForEvent("pointermove", checkPointerEvent), 69 promiseForEvent("pointerup", checkPointerEvent), 70 promiseForEvent("pointerout", checkPointerEvent), 71 promiseForEvent("pointerleave", checkPointerEvent), 72 ]; 73 74 synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 }); 75 synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 }); 76 synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_TOUCH, pressure: 0.75 }); 77 78 await Promise.all(eventPromises); 79 } 80 81 // A test for pointercancel event. 82 async function doTestForTouchPointerCancelEvent() { 83 let eventPromises = [ 84 promiseForEvent("pointerover", checkPointerEvent), 85 promiseForEvent("pointerenter", checkPointerEvent), 86 promiseForEvent("pointerdown", checkPointerEvent), 87 promiseForEvent("pointermove", checkPointerEvent), 88 promiseForEvent("pointercancel", checkPointerEvent), 89 promiseForEvent("pointerout", checkPointerEvent), 90 promiseForEvent("pointerleave", checkPointerEvent), 91 ]; 92 93 synthesizeTouch(target0, 5, 5, { type: "touchstart" }); 94 synthesizeTouch(target0, 6, 6, { type: "touchmove" }); 95 synthesizeTouch(target0, 6, 6, { type: "touchcancel" }); 96 97 await Promise.all(eventPromises); 98 } 99 100 // A test for pointer events from pen interface. 101 async function doTestForPenPointerEvent() { 102 let eventPromises = [ 103 promiseForEvent("pointerover", checkPointerEvent), 104 promiseForEvent("pointerenter", checkPointerEvent), 105 promiseForEvent("pointerdown", checkPointerEvent), 106 promiseForEvent("pointermove", checkPointerEvent), 107 promiseForEvent("pointerup", checkPointerEvent), 108 promiseForEvent("pointerout", checkPointerEvent), 109 promiseForEvent("pointerleave", checkPointerEvent), 110 ]; 111 112 synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_PEN }); 113 synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_PEN }); 114 synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_PEN }); 115 synthesizeMouse(target1, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_PEN }); 116 117 await Promise.all(eventPromises); 118 } 119 120 // A test for gotpointercapture and lostpointercapture events. 121 // We would also test releasePointerCapture for only accepting spoofed pointer 122 // Id here. 123 async function doTestForPointerCapture() { 124 // We test for both mouse and touch to see whether the capture events are 125 // filed properly. We don't check pen here since it won't file capture 126 // events. 127 let inputSources = [ MouseEvent.MOZ_SOURCE_MOUSE, 128 MouseEvent.MOZ_SOURCE_TOUCH ]; 129 130 for (let inputSource of inputSources) { 131 function eventHandler(event) { 132 checkPointerEvent(event); 133 if (event.type === "pointerdown") { 134 target0.setPointerCapture(event.pointerId); 135 } else if (event.type === "pointermove") { 136 if (inputSource === MouseEvent.MOZ_SOURCE_TOUCH) { 137 try { 138 target0.releasePointerCapture(utils.DEFAULT_TOUCH_POINTER_ID); 139 ok(false, "The releasePointerCapture should fail here, but it is not."); 140 } catch (e) { 141 ok(true, "The releasePointerCapture fails properly."); 142 } 143 } 144 target0.releasePointerCapture(event.pointerId); 145 } 146 } 147 148 let eventPromises = [ 149 promiseForEvent("pointerover", eventHandler), 150 promiseForEvent("pointerenter", eventHandler), 151 promiseForEvent("pointerdown", eventHandler), 152 promiseForEvent("gotpointercapture", eventHandler), 153 promiseForEvent("pointermove", eventHandler), 154 promiseForEvent("lostpointercapture", eventHandler), 155 promiseForEvent("pointerup", eventHandler), 156 promiseForEvent("pointerout", eventHandler), 157 promiseForEvent("pointerleave", eventHandler), 158 ]; 159 160 synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource }); 161 synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource }); 162 synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource }); 163 synthesizeMouse(target1, 5, 5, { type: "mousemove", inputSource }); 164 165 await Promise.all(eventPromises); 166 } 167 } 168 169 // A test for setPointerCapture() for only accepting spoofed pointer id. 170 async function doTestForSetPointerCapture() { 171 function eventHandler(event) { 172 checkPointerEvent(event); 173 if (event.type === "pointerdown") { 174 try { 175 target0.setPointerCapture(utils.DEFAULT_TOUCH_POINTER_ID); 176 ok(false, "The setPointerCapture should fail here, but it is not."); 177 } catch (e) { 178 ok(true, "The setPointerCapture fails properly."); 179 } 180 } 181 } 182 183 let eventPromises = [ 184 promiseForEvent("pointerover", eventHandler), 185 promiseForEvent("pointerenter", eventHandler), 186 promiseForEvent("pointerdown", eventHandler), 187 promiseForEvent("pointermove", eventHandler), 188 promiseForEvent("pointerup", eventHandler), 189 promiseForEvent("pointerout", eventHandler), 190 promiseForEvent("pointerleave", eventHandler), 191 ]; 192 193 synthesizeMouse(target0, 5, 5, { type: "mousedown", inputSource: MouseEvent.MOZ_SOURCE_TOUCH }); 194 synthesizeMouse(target0, 5, 5, { type: "mousemove", inputSource: MouseEvent.MOZ_SOURCE_TOUCH }); 195 synthesizeMouse(target0, 5, 5, { type: "mouseup", inputSource: MouseEvent.MOZ_SOURCE_TOUCH }); 196 197 await Promise.all(eventPromises); 198 } 199 200 // A test for assuring that script generated events won't be spoofed. 201 function doTestNoSpoofingForScriptGeneratedEvent() { 202 return new Promise(resolve => { 203 // Generate a custom pointer event by script. 204 let pointerEventCustom = new PointerEvent("pointerover", { 205 pointerId: utils.DEFAULT_TOUCH_POINTER_ID, 206 pointerType: "touch", 207 width: 5, 208 height: 5, 209 pressure: 0.75, 210 tangentialPressure: 0.5, 211 isPrimary: false, 212 }); 213 214 target0.addEventListener("pointerover", (event) => { 215 // Check that script generated event is not spoofed. 216 is(event.pointerType, "touch", "The pointerEvent.pointerType is not spoofed."); 217 is(event.width, 5, "The pointerEvent.width is not spoofed."); 218 is(event.height, 5, "The pointerEvent.height is not spoofed."); 219 is(event.pressure, 0.75, "The pointerEvent.pressure is not spoofed."); 220 is(event.tangentialPressure, 0.5, "The pointerEvent.tangentialPressure is not spoofed."); 221 is(event.isPrimary, false, "The pointerEvent.isPrimary is not spoofed."); 222 resolve(); 223 }, { once: true }); 224 225 target0.dispatchEvent(pointerEventCustom); 226 }); 227 } 228 229 async function doTests() { 230 await doTestForTouchPointerEvent(); 231 await doTestForTouchPointerCancelEvent(); 232 await doTestForPenPointerEvent(); 233 await doTestForPointerCapture(); 234 await doTestForSetPointerCapture(); 235 await doTestNoSpoofingForScriptGeneratedEvent(); 236 237 SimpleTest.finish(); 238 } 239 240 SimpleTest.waitForFocus(() => { 241 SpecialPowers.pushPrefEnv({"set": [["privacy.resistFingerprinting", true]]}, 242 doTests); 243 }); 244 245 </script> 246 </body> 247 </html>