Bug 1670295 - [marionette] Move legacy touch helpers from listener.js to legacyaction.js r=marionette-reviewers,whimboo,maja_zf

Depends on D93324

Move singleTap and dependencies to legacyaction.js in order to reuse them in the JSWindowActor.

Differential Revision: https://phabricator.services.mozilla.com/D93365
This commit is contained in:
Julian Descottes 2020-10-14 22:22:15 +00:00
Родитель b932959de4
Коммит 891c58ed1a
2 изменённых файлов: 127 добавлений и 121 удалений

Просмотреть файл

@ -15,6 +15,7 @@ const { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
Preferences: "resource://gre/modules/Preferences.jsm",
accessibility: "chrome://marionette/content/accessibility.js",
element: "chrome://marionette/content/element.js",
error: "chrome://marionette/content/error.js",
evaluate: "chrome://marionette/content/evaluate.js",
@ -52,19 +53,49 @@ action.Chain = function() {
this.inputSource = null;
};
/**
* Create a touch based event.
*
* @param {Element} elem
* The Element on which the touch event should be created.
* @param {Number} x
* x coordinate relative to the viewport.
* @param {Number} y
* y coordinate relative to the viewport.
* @param {Number} touchId
* Touch event id used by legacyactions.
*/
action.Chain.prototype.createATouch = function(elem, x, y, touchId) {
const doc = elem.ownerDocument;
const win = doc.defaultView;
const [
clientX,
clientY,
pageX,
pageY,
screenX,
screenY,
] = this.getCoordinateInfo(elem, x, y);
const atouch = doc.createTouch(
win,
elem,
touchId,
pageX,
pageY,
screenX,
screenY,
clientX,
clientY
);
return atouch;
};
action.Chain.prototype.dispatchActions = function(
args,
touchId,
container,
seenEls,
touchProvider
seenEls
) {
// Some touch events code in the listener needs to do ipc, so we can't
// share this code across chrome/content.
if (touchProvider) {
this.touchProvider = touchProvider;
}
this.seenEls = seenEls;
this.container = container;
let commandArray = evaluate.fromJSON(args, seenEls, container.frame);
@ -145,16 +176,82 @@ action.Chain.prototype.emitMouseEvent = function(
);
};
action.Chain.prototype.emitTouchEvent = function(doc, type, touch) {
logger.info(
`Emitting Touch event of type ${type} ` +
`to element with id: ${touch.target.id} ` +
`and tag name: ${touch.target.tagName} ` +
`at coordinates (${touch.clientX}), ` +
`${touch.clientY}) relative to the viewport`
);
const win = doc.defaultView;
if (win.docShell.asyncPanZoomEnabled && this.scrolling) {
logger.debug(
`Cannot emit touch event with asyncPanZoomEnabled and legacyactions.scrolling`
);
return;
}
// we get here if we're not in asyncPacZoomEnabled land, or if we're
// the main process
win.windowUtils.sendTouchEvent(
type,
[touch.identifier],
[touch.clientX],
[touch.clientY],
[touch.radiusX],
[touch.radiusY],
[touch.rotationAngle],
[touch.force],
0
);
};
/**
* Reset any persisted values after a command completes.
*/
action.Chain.prototype.resetValues = function() {
this.container = null;
this.seenEls = null;
this.touchProvider = null;
this.mouseEventsOnly = false;
};
/**
* Function that performs a single tap.
*/
action.Chain.prototype.singleTap = async function(
el,
corx,
cory,
capabilities
) {
const doc = el.ownerDocument;
// after this block, the element will be scrolled into view
let visible = element.isVisible(el, corx, cory);
if (!visible) {
throw new error.ElementNotInteractableError(
"Element is not currently visible and may not be manipulated"
);
}
let a11y = accessibility.get(capabilities["moz:accessibilityChecks"]);
let acc = await a11y.getAccessible(el, true);
a11y.assertVisible(acc, el, visible);
a11y.assertActionable(acc, el);
if (!doc.createTouch) {
this.mouseEventsOnly = true;
}
let c = element.coordinates(el, corx, cory);
if (!this.mouseEventsOnly) {
let touchId = this.nextTouchId++;
let touch = this.createATouch(el, c.x, c.y, touchId);
this.emitTouchEvent(doc, "touchstart", touch);
this.emitTouchEvent(doc, "touchend", touch);
}
this.mouseTap(doc, c.x, c.y);
};
/**
* Emit events for each action in the provided chain.
*
@ -386,7 +483,7 @@ action.Chain.prototype.generateEvents = function(
switch (type) {
case "tap":
if (this.mouseEventsOnly) {
let touch = this.touchProvider.createATouch(target, x, y, touchId);
let touch = this.createATouch(target, x, y, touchId);
this.mouseTap(
touch.target.ownerDocument,
touch.clientX,
@ -397,9 +494,9 @@ action.Chain.prototype.generateEvents = function(
);
} else {
touchId = this.nextTouchId++;
let touch = this.touchProvider.createATouch(target, x, y, touchId);
this.touchProvider.emitTouchEvent("touchstart", touch);
this.touchProvider.emitTouchEvent("touchend", touch);
let touch = this.createATouch(target, x, y, touchId);
this.emitTouchEvent(doc, "touchstart", touch);
this.emitTouchEvent(doc, "touchend", touch);
this.mouseTap(
touch.target.ownerDocument,
touch.clientX,
@ -419,8 +516,8 @@ action.Chain.prototype.generateEvents = function(
this.emitMouseEvent(doc, "mousedown", x, y, null, null, keyModifiers);
} else {
touchId = this.nextTouchId++;
let touch = this.touchProvider.createATouch(target, x, y, touchId);
this.touchProvider.emitTouchEvent("touchstart", touch);
let touch = this.createATouch(target, x, y, touchId);
this.emitTouchEvent(doc, "touchstart", touch);
this.touchIds[touchId] = touch;
return touchId;
}
@ -434,8 +531,8 @@ action.Chain.prototype.generateEvents = function(
let touch = this.touchIds[touchId];
let [x, y] = this.lastCoordinates;
touch = this.touchProvider.createATouch(touch.target, x, y, touchId);
this.touchProvider.emitTouchEvent("touchend", touch);
touch = this.createATouch(touch.target, x, y, touchId);
this.emitTouchEvent(doc, "touchend", touch);
if (this.isTap) {
this.mouseTap(
@ -460,10 +557,7 @@ action.Chain.prototype.generateEvents = function(
let [x, y] = this.lastCoordinates;
this.emitMouseEvent(doc, "mouseup", x, y, null, null, keyModifiers);
} else {
this.touchProvider.emitTouchEvent(
"touchcancel",
this.touchIds[touchId]
);
this.emitTouchEvent(doc, "touchcancel", this.touchIds[touchId]);
delete this.touchIds[touchId];
}
this.lastCoordinates = null;
@ -474,14 +568,14 @@ action.Chain.prototype.generateEvents = function(
if (this.mouseEventsOnly) {
this.emitMouseEvent(doc, "mousemove", x, y, null, null, keyModifiers);
} else {
let touch = this.touchProvider.createATouch(
let touch = this.createATouch(
this.touchIds[touchId].target,
x,
y,
touchId
);
this.touchIds[touchId] = touch;
this.touchProvider.emitTouchEvent("touchmove", touch);
this.emitTouchEvent(doc, "touchmove", touch);
}
break;

Просмотреть файл

@ -317,94 +317,11 @@ async function executeScript(script, args, opts = {}) {
return evaluate.sandbox(sb, script, args, opts);
}
function emitTouchEvent(type, touch) {
logger.info(
`Emitting Touch event of type ${type} ` +
`to element with id: ${touch.target.id} ` +
`and tag name: ${touch.target.tagName} ` +
`at coordinates (${touch.clientX}), ` +
`${touch.clientY}) relative to the viewport`
);
const win = curContainer.frame;
if (win.docShell.asyncPanZoomEnabled && legacyactions.scrolling) {
logger.debug(
`Cannot emit touch event with asyncPanZoomEnabled and legacyactions.scrolling`
);
return;
}
// we get here if we're not in asyncPacZoomEnabled land, or if we're
// the main process
win.windowUtils.sendTouchEvent(
type,
[touch.identifier],
[touch.clientX],
[touch.clientY],
[touch.radiusX],
[touch.radiusY],
[touch.rotationAngle],
[touch.force],
0
);
}
/**
* Function that perform a single tap
* Function that performs a single tap.
*/
async function singleTap(el, corx, cory, capabilities) {
// after this block, the element will be scrolled into view
let visible = element.isVisible(el, corx, cory);
if (!visible) {
throw new error.ElementNotInteractableError(
"Element is not currently visible and may not be manipulated"
);
}
let a11y = accessibility.get(capabilities["moz:accessibilityChecks"]);
let acc = await a11y.getAccessible(el, true);
a11y.assertVisible(acc, el, visible);
a11y.assertActionable(acc, el);
if (!curContainer.frame.document.createTouch) {
legacyactions.mouseEventsOnly = true;
}
let c = element.coordinates(el, corx, cory);
if (!legacyactions.mouseEventsOnly) {
let touchId = legacyactions.nextTouchId++;
let touch = createATouch(el, c.x, c.y, touchId);
emitTouchEvent("touchstart", touch);
emitTouchEvent("touchend", touch);
}
legacyactions.mouseTap(el.ownerDocument, c.x, c.y);
}
/**
* Function to create a touch based on the element
* corx and cory are relative to the viewport, id is the touchId
*/
function createATouch(el, corx, cory, touchId) {
let doc = el.ownerDocument;
let win = doc.defaultView;
let [
clientX,
clientY,
pageX,
pageY,
screenX,
screenY,
] = legacyactions.getCoordinateInfo(el, corx, cory);
let atouch = doc.createTouch(
win,
el,
touchId,
pageX,
pageY,
screenX,
screenY,
clientX,
clientY
);
return atouch;
return legacyactions.singleTap(el, corx, cory, capabilities);
}
/**
@ -447,17 +364,7 @@ async function releaseActions() {
* Start action chain on one finger.
*/
function actionChain(chain, touchId) {
let touchProvider = {};
touchProvider.createATouch = createATouch;
touchProvider.emitTouchEvent = emitTouchEvent;
return legacyactions.dispatchActions(
chain,
touchId,
curContainer,
seenEls,
touchProvider
);
return legacyactions.dispatchActions(chain, touchId, curContainer, seenEls);
}
function emitMultiEvents(type, touch, touches) {
@ -534,7 +441,7 @@ function setDispatch(batches, touches, batchIndex = 0) {
case "press":
el = seenEls.get(pack[2], curContainer.frame);
c = element.coordinates(el, pack[3], pack[4]);
touch = createATouch(el, c.x, c.y, touchId);
touch = legacyactions.createATouch(el, c.x, c.y, touchId);
multiLast[touchId] = touch;
touches.push(touch);
emitMultiEvents("touchstart", touch, touches);
@ -552,7 +459,12 @@ function setDispatch(batches, touches, batchIndex = 0) {
case "move":
el = seenEls.get(pack[2], curContainer.frame);
c = element.coordinates(el);
touch = createATouch(multiLast[touchId].target, c.x, c.y, touchId);
touch = legacyactions.createATouch(
multiLast[touchId].target,
c.x,
c.y,
touchId
);
touchIndex = touches.indexOf(lastTouch);
touches[touchIndex] = touch;
multiLast[touchId] = touch;