From 40a355a42d4a9444dc753c04c6608dade2f06a23 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:27 +0200 Subject: Adding upstream version 125.0.1. Signed-off-by: Daniel Baumann --- testing/mochitest/tests/SimpleTest/EventUtils.js | 360 ++++++++++++++++------- 1 file changed, 257 insertions(+), 103 deletions(-) (limited to 'testing/mochitest/tests/SimpleTest/EventUtils.js') diff --git a/testing/mochitest/tests/SimpleTest/EventUtils.js b/testing/mochitest/tests/SimpleTest/EventUtils.js index 739c7052ea..8833b8bc59 100644 --- a/testing/mochitest/tests/SimpleTest/EventUtils.js +++ b/testing/mochitest/tests/SimpleTest/EventUtils.js @@ -1,3 +1,4 @@ +/* eslint-disable no-nested-ternary */ /** * EventUtils provides some utility methods for creating and sending DOM events. * @@ -569,14 +570,86 @@ function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow) { aWindow ); } -function synthesizeTouch(aTarget, aOffsetX, aOffsetY, aEvent, aWindow) { - var rect = aTarget.getBoundingClientRect(); - return synthesizeTouchAtPoint( - rect.left + aOffsetX, - rect.top + aOffsetY, - aEvent, - aWindow - ); + +/** + * Synthesize one or more touches on aTarget. aTarget can be either Element + * or Array of Elements. aOffsetX, aOffsetY, aEvent.id, aEvent.rx, aEvent.ry, + * aEvent.angle, aEvent.force, aEvent.tiltX, aEvent.tiltY and aEvent.twist can + * be either Number or Array of Numbers (can be mixed). If you specify array + * to synthesize a multi-touch, you need to specify same length arrays. If + * you don't specify array to them, same values (or computed default values for + * aEvent.id) are used for all touches. + * + * @param {Element | Element[]} aTarget The target element which you specify + * relative offset from its top-left. + * @param {Number | Number[]} aOffsetX The relative offset from left of aTarget. + * @param {Number | Number[]} aOffsetY The relative offset from top of aTarget. + * @param {Object} aEvent + * type: The touch event type. If undefined, "touchstart" and "touchend" will + * be synthesized at same point. + * + * id: The touch id. If you don't specify this, default touch id will be used + * for first touch and further touch ids are the values incremented from the + * first id. + * + * rx, ry: The radii of the touch. + * + * angle: The angle in degree. + * + * force: The force of the touch. If the type is "touchend", this should be 0. + * If unspecified, this is default to 0 for "touchend" or 1 for the others. + * + * tiltX, tiltY: The tilt of the touch. + * + * twist: The twist of the touch. + * @param {Window} aWindow Default to `window`. + * @returns true if and only if aEvent.type is specified and default of the + * event is prevented. + */ +function synthesizeTouch( + aTarget, + aOffsetX, + aOffsetY, + aEvent = {}, + aWindow = window +) { + let rectX, rectY; + if (Array.isArray(aTarget)) { + let lastTarget, lastTargetRect; + aTarget.forEach(target => { + const rect = + target == lastTarget ? lastTargetRect : target.getBoundingClientRect(); + rectX.push(rect.left); + rectY.push(rect.top); + lastTarget = target; + lastTargetRect = rect; + }); + } else { + const rect = aTarget.getBoundingClientRect(); + rectX = [rect.left]; + rectY = [rect.top]; + } + const offsetX = (() => { + if (Array.isArray(aOffsetX)) { + let ret = []; + aOffsetX.forEach((value, index) => { + ret.push(value + rectX[Math.min(index, rectX.length - 1)]); + }); + return ret; + } + return aOffsetX + rectX[0]; + })(); + const offsetY = (() => { + if (Array.isArray(aOffsetY)) { + let ret = []; + aOffsetY.forEach((value, index) => { + ret.push(value + rectY[Math.min(index, rectY.length - 1)]); + }); + return ret; + } + return aOffsetY + rectY[0]; + })(); + return synthesizeTouchAtPoint(offsetX, offsetY, aEvent, aWindow); } /** @@ -776,68 +849,160 @@ function synthesizeMouseAtPoint(left, top, aEvent, aWindow = window) { return defaultPrevented; } -function synthesizeTouchAtPoint(left, top, aEvent, aWindow = window) { - var utils = _getDOMWindowUtils(aWindow); - let defaultPrevented = false; +/** + * Synthesize one or more touches at the points. aLeft, aTop, aEvent.id, + * aEvent.rx, aEvent.ry, aEvent.angle, aEvent.force, aEvent.tiltX, aEvent.tiltY + * and aEvent.twist can be either Number or Array of Numbers (can be mixed). + * If you specify array to synthesize a multi-touch, you need to specify same + * length arrays. If you don't specify array to them, same values are used for + * all touches. + * + * @param {Element | Element[]} aTarget The target element which you specify + * relative offset from its top-left. + * @param {Number | Number[]} aOffsetX The relative offset from left of aTarget. + * @param {Number | Number[]} aOffsetY The relative offset from top of aTarget. + * @param {Object} aEvent + * type: The touch event type. If undefined, "touchstart" and "touchend" will + * be synthesized at same point. + * + * id: The touch id. If you don't specify this, default touch id will be used + * for first touch and further touch ids are the values incremented from the + * first id. + * + * rx, ry: The radii of the touch. + * + * angle: The angle in degree. + * + * force: The force of the touch. If the type is "touchend", this should be 0. + * If unspecified, this is default to 0 for "touchend" or 1 for the others. + * + * tiltX, tiltY: The tilt of the touch. + * + * twist: The twist of the touch. + * @param {Window} aWindow Default to `window`. + * @returns true if and only if aEvent.type is specified and default of the + * event is prevented. + */ +function synthesizeTouchAtPoint(aLeft, aTop, aEvent = {}, aWindow = window) { + let utils = _getDOMWindowUtils(aWindow); + if (!utils) { + return false; + } - if (utils) { - var id = aEvent.id || utils.DEFAULT_TOUCH_POINTER_ID; - var rx = aEvent.rx || 1; - var ry = aEvent.ry || 1; - var angle = aEvent.angle || 0; - var force = aEvent.force || (aEvent.type === "touchend" ? 0 : 1); - var tiltX = aEvent.tiltX || 0; - var tiltY = aEvent.tiltY || 0; - var twist = aEvent.twist || 0; - var modifiers = _parseModifiers(aEvent, aWindow); + if ( + Array.isArray(aLeft) && + Array.isArray(aTop) && + aLeft.length != aTop.length + ) { + throw new Error(`aLeft and aTop should be same length array`); + } - if ("type" in aEvent && aEvent.type) { - defaultPrevented = utils.sendTouchEvent( - aEvent.type, - [id], - [left], - [top], - [rx], - [ry], - [angle], - [force], - [tiltX], - [tiltY], - [twist], - modifiers - ); - } else { - utils.sendTouchEvent( - "touchstart", - [id], - [left], - [top], - [rx], - [ry], - [angle], - [force], - [tiltX], - [tiltY], - [twist], - modifiers - ); - utils.sendTouchEvent( - "touchend", - [id], - [left], - [top], - [rx], - [ry], - [angle], - [force], - [tiltX], - [tiltY], - [twist], - modifiers + const arrayLength = Array.isArray(aLeft) + ? aLeft.length + : Array.isArray(aTop) + ? aTop.length + : 1; + + function throwExceptionIfDifferentLengthArray(aArray, aName) { + if (Array.isArray(aArray) && arrayLength !== aArray.length) { + throw new Error(`${aName} is different length array`); + } + } + const leftArray = (() => { + if (Array.isArray(aLeft)) { + return aLeft; + } + return new Array(arrayLength).fill(aLeft); + })(); + const topArray = (() => { + if (Array.isArray(aTop)) { + throwExceptionIfDifferentLengthArray(aTop, "aTop"); + return aTop; + } + return new Array(arrayLength).fill(aTop); + })(); + const idArray = (() => { + if ("id" in aEvent && Array.isArray(aEvent.id)) { + throwExceptionIfDifferentLengthArray(aEvent.id, "aEvent.id"); + return aEvent.id; + } + let id = aEvent.id || utils.DEFAULT_TOUCH_POINTER_ID; + let ret = []; + for (let i = 0; i < arrayLength; i++) { + ret.push(id++); + } + return ret; + })(); + function getSameLengthArrayOfEventProperty(aProperty, aDefaultValue) { + if (aProperty in aEvent && Array.isArray(aEvent[aProperty])) { + throwExceptionIfDifferentLengthArray( + aEvent.rx, + arrayLength, + `aEvent.${aProperty}` ); + return aEvent[aProperty]; } + return new Array(arrayLength).fill(aEvent[aProperty] || aDefaultValue); } - return defaultPrevented; + const rxArray = getSameLengthArrayOfEventProperty("rx", 1); + const ryArray = getSameLengthArrayOfEventProperty("ry", 1); + const angleArray = getSameLengthArrayOfEventProperty("angle", 0); + const forceArray = getSameLengthArrayOfEventProperty( + "force", + aEvent.type === "touchend" ? 0 : 1 + ); + const tiltXArray = getSameLengthArrayOfEventProperty("tiltX", 0); + const tiltYArray = getSameLengthArrayOfEventProperty("tiltY", 0); + const twistArray = getSameLengthArrayOfEventProperty("twist", 0); + + const modifiers = _parseModifiers(aEvent, aWindow); + + if ("type" in aEvent && aEvent.type) { + return utils.sendTouchEvent( + aEvent.type, + idArray, + leftArray, + topArray, + rxArray, + ryArray, + angleArray, + forceArray, + tiltXArray, + tiltYArray, + twistArray, + modifiers + ); + } + + utils.sendTouchEvent( + "touchstart", + idArray, + leftArray, + topArray, + rxArray, + ryArray, + angleArray, + forceArray, + tiltXArray, + tiltYArray, + twistArray, + modifiers + ); + utils.sendTouchEvent( + "touchend", + idArray, + leftArray, + topArray, + rxArray, + ryArray, + angleArray, + forceArray, + tiltXArray, + tiltYArray, + twistArray, + modifiers + ); + return false; } // Call synthesizeMouse with coordinates at the center of aTarget. @@ -851,7 +1016,7 @@ function synthesizeMouseAtCenter(aTarget, aEvent, aWindow) { aWindow ); } -function synthesizeTouchAtCenter(aTarget, aEvent, aWindow) { +function synthesizeTouchAtCenter(aTarget, aEvent = {}, aWindow = window) { var rect = aTarget.getBoundingClientRect(); synthesizeTouchAtPoint( rect.left + rect.width / 2, @@ -1020,7 +1185,9 @@ function _sendWheelAndPaint( } var onwheel = function () { - SpecialPowers.removeSystemEventListener(window, "wheel", onwheel); + SpecialPowers.wrap(window).removeEventListener("wheel", onwheel, { + mozSystemGroup: true, + }); // Wait one frame since the wheel event has not caused a refresh observer // to be added yet. @@ -1055,7 +1222,9 @@ function _sendWheelAndPaint( // Listen for the system wheel event, because it happens after all of // the other wheel events, including legacy events. - SpecialPowers.addSystemEventListener(aWindow, "wheel", onwheel); + SpecialPowers.wrap(aWindow).addEventListener("wheel", onwheel, { + mozSystemGroup: true, + }); if (aFlushMode === _FlushModes.FLUSH) { synthesizeWheel(aTarget, aOffsetX, aOffsetY, aEvent, aWindow); } else { @@ -1405,13 +1574,10 @@ function synthesizeAndWaitNativeMouseMove( ); let eventRegisteredPromise = new Promise(resolve => { - mm.addMessageListener( - "Test:MouseMoveRegistered", - function processed(message) { - mm.removeMessageListener("Test:MouseMoveRegistered", processed); - resolve(); - } - ); + mm.addMessageListener("Test:MouseMoveRegistered", function processed() { + mm.removeMessageListener("Test:MouseMoveRegistered", processed); + resolve(); + }); }); let eventReceivedPromise = ContentTask.spawn( browser, @@ -1579,7 +1745,7 @@ function synthesizeAndWaitKey( ); let keyRegisteredPromise = new Promise(resolve => { - mm.addMessageListener("Test:KeyRegistered", function processed(message) { + mm.addMessageListener("Test:KeyRegistered", function processed() { mm.removeMessageListener("Test:KeyRegistered", processed); resolve(); }); @@ -3853,21 +4019,19 @@ async function synthesizePlainDragAndCancel( aExpectedDataTransferItems ); } - SpecialPowers.addSystemEventListener( - srcElement.ownerDocument, + SpecialPowers.wrap(srcElement.ownerDocument).addEventListener( "dragstart", onDragStart, - { capture: true } + { capture: true, mozSystemGroup: true } ); try { aParams.expectCancelDragStart = true; await synthesizePlainDragAndDrop(aParams); } finally { - SpecialPowers.removeSystemEventListener( - srcElement.ownerDocument, + SpecialPowers.wrap(srcElement.ownerDocument).removeEventListener( "dragstart", onDragStart, - { capture: true } + { capture: true, mozSystemGroup: true } ); } return result; @@ -3884,33 +4048,23 @@ class EventCounter { // SpecialPowers is picky and needs to be passed an explicit reference to // the function to be called. To avoid having to bind "this", we therefore // define the method this way, via a property. - this.handleEvent = aEvent => { + this.handleEvent = () => { this.eventCount++; }; - if (aOptions.mozSystemGroup) { - SpecialPowers.addSystemEventListener( - aTarget, - aType, - this.handleEvent, - aOptions.capture - ); - } else { - aTarget.addEventListener(aType, this, aOptions); - } + SpecialPowers.wrap(aTarget).addEventListener( + aType, + this.handleEvent, + aOptions + ); } unregister() { - if (this.options.mozSystemGroup) { - SpecialPowers.removeSystemEventListener( - this.target, - this.type, - this.handleEvent, - this.options.capture - ); - } else { - this.target.removeEventListener(this.type, this, this.options); - } + SpecialPowers.wrap(this.target).removeEventListener( + this.type, + this.handleEvent, + this.options + ); } get count() { -- cgit v1.2.3