--- a/testing/marionette/action.js
+++ b/testing/marionette/action.js
@@ -956,31 +956,30 @@ action.Mouse = class {
* tick's actions are not dispatched until the Promise for the current
* tick is resolved.
*
* @param {action.Chain} chain
* Actions grouped by tick; each element in |chain| is a sequence of
* actions for one tick.
* @param {element.Store} seenEls
* Element store.
- * @param {Object.<string, nsIDOMWindow>} container
- * Object with <code>frame</code> property of type
- * <code>nsIDOMWindow</code>.
+ * @param {WindowProxy} window
+ * Current window global.
*
* @return {Promise}
* Promise for dispatching all actions in |chain|.
*/
-action.dispatch = function(chain, seenEls, container) {
+action.dispatch = function(chain, seenEls, window) {
let chainEvents = (async () => {
for (let tickActions of chain) {
await action.dispatchTickActions(
tickActions,
action.computeTickDuration(tickActions),
seenEls,
- container);
+ window);
}
})();
return chainEvents;
};
/**
* Dispatch sequence of actions for one tick.
*
@@ -993,29 +992,28 @@ action.dispatch = function(chain, seenEl
* different durations and therefore may not end in the same order.
*
* @param {Array.<action.Action>} tickActions
* List of actions for one tick.
* @param {number} tickDuration
* Duration in milliseconds of this tick.
* @param {element.Store} seenEls
* Element store.
- * @param {Object.<string, nsIDOMWindow>} container
- * Object with <code>frame</code> property of type
- * <code>nsIDOMWindow</code>.
+ * @param {WindowProxy} window
+ * Current window global.
*
* @return {Promise}
* Promise for dispatching all tick-actions and pending DOM events.
*/
action.dispatchTickActions = function(
- tickActions, tickDuration, seenEls, container) {
+ tickActions, tickDuration, seenEls, window) {
let pendingEvents = tickActions.map(
- toEvents(tickDuration, seenEls, container));
+ toEvents(tickDuration, seenEls, window));
return Promise.all(pendingEvents).then(
- () => interaction.flushEventLoop(container.frame));
+ () => interaction.flushEventLoop(window));
};
/**
* Compute tick duration in milliseconds for a collection of actions.
*
* @param {Array.<action.Action>} tickActions
* List of actions for one tick.
*
@@ -1071,50 +1069,51 @@ action.computePointerDestination = funct
/**
* Create a closure to use as a map from action definitions to Promise events.
*
* @param {number} tickDuration
* Duration in milliseconds of this tick.
* @param {element.Store} seenEls
* Element store.
- * @param {Object.<string, nsIDOMWindow>} container
- * Object with <code>frame</code> property of type
- * <code>nsIDOMWindow</code>.
+ * @param {WindowProxy} window
+ * Current window global.
*
* @return {function(action.Action): Promise}
* Function that takes an action and returns a Promise for dispatching
* the event that corresponds to that action.
*/
-function toEvents(tickDuration, seenEls, container) {
+function toEvents(tickDuration, seenEls, window) {
return a => {
let inputState = action.inputStateMap.get(a.id);
+
switch (a.subtype) {
case action.KeyUp:
- return dispatchKeyUp(a, inputState, container.frame);
+ return dispatchKeyUp(a, inputState, window);
case action.KeyDown:
- return dispatchKeyDown(a, inputState, container.frame);
+ return dispatchKeyDown(a, inputState, window);
case action.PointerDown:
- return dispatchPointerDown(a, inputState, container.frame);
+ return dispatchPointerDown(a, inputState, window);
case action.PointerUp:
- return dispatchPointerUp(a, inputState, container.frame);
+ return dispatchPointerUp(a, inputState, window);
case action.PointerMove:
return dispatchPointerMove(
- a, inputState, tickDuration, seenEls, container);
+ a, inputState, tickDuration, seenEls, window);
case action.PointerCancel:
throw new UnsupportedOperationError();
case action.Pause:
return dispatchPause(a, tickDuration);
}
+
return undefined;
};
}
/**
* Dispatch a keyDown action equivalent to pressing a key on a keyboard.
*
* @param {action.Action} a
@@ -1282,73 +1281,77 @@ function dispatchPointerUp(a, inputState
* with the pointer coordinates being updated around 60 times per second.
*
* @param {action.Action} a
* Action to dispatch.
* @param {action.InputState} inputState
* Input state for this action's input source.
* @param {element.Store} seenEls
* Element store.
- * @param {Object.<string, nsIDOMWindow>} container
- * Object with <code>frame</code> property of type
- * <code>nsIDOMWindow</code>.
+ * @param {WindowProxy} window
+ * Current window global.
*
* @return {Promise}
* Promise to dispatch at least one pointermove event, as well as
* mousemove events as appropriate.
*/
-function dispatchPointerMove(
- a, inputState, tickDuration, seenEls, container) {
+function dispatchPointerMove(a, inputState, tickDuration, seenEls, window) {
const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
// interval between pointermove increments in ms, based on common vsync
const fps60 = 17;
+
return new Promise(resolve => {
const start = Date.now();
const [startX, startY] = [inputState.x, inputState.y];
+
let target = action.computePointerDestination(a, inputState,
- getElementCenter(a.origin, seenEls, container));
+ getElementCenter(a.origin, seenEls, window));
const [targetX, targetY] = [target.x, target.y];
- if (!inViewPort(targetX, targetY, container.frame)) {
+
+ if (!inViewPort(targetX, targetY, window)) {
throw new MoveTargetOutOfBoundsError(
`(${targetX}, ${targetY}) is out of bounds of viewport ` +
- `width (${container.frame.innerWidth}) ` +
- `and height (${container.frame.innerHeight})`);
+ `width (${window.innerWidth}) ` +
+ `and height (${window.innerHeight})`);
}
const duration = typeof a.duration == "undefined" ? tickDuration : a.duration;
if (duration === 0) {
// move pointer to destination in one step
- performOnePointerMove(inputState, targetX, targetY, container.frame);
+ performOnePointerMove(inputState, targetX, targetY, window);
resolve();
return;
}
const distanceX = targetX - startX;
const distanceY = targetY - startY;
const ONE_SHOT = Ci.nsITimer.TYPE_ONE_SHOT;
let intermediatePointerEvents = (async () => {
// wait |fps60| ms before performing first incremental pointer move
await new Promise(resolveTimer =>
timer.initWithCallback(resolveTimer, fps60, ONE_SHOT));
+
let durationRatio = Math.floor(Date.now() - start) / duration;
const epsilon = fps60 / duration / 10;
while ((1 - durationRatio) > epsilon) {
let x = Math.floor(durationRatio * distanceX + startX);
let y = Math.floor(durationRatio * distanceY + startY);
- performOnePointerMove(inputState, x, y, container.frame);
+ performOnePointerMove(inputState, x, y, window);
// wait |fps60| ms before performing next pointer move
await new Promise(resolveTimer =>
timer.initWithCallback(resolveTimer, fps60, ONE_SHOT));
+
durationRatio = Math.floor(Date.now() - start) / duration;
}
})();
+
// perform last pointer move after all incremental moves are resolved and
// durationRatio is close enough to 1
intermediatePointerEvents.then(() => {
- performOnePointerMove(inputState, targetX, targetY, container.frame);
+ performOnePointerMove(inputState, targetX, targetY, window);
resolve();
});
});
}
function performOnePointerMove(inputState, targetX, targetY, win) {
if (targetX == inputState.x && targetY == inputState.y) {
@@ -1404,17 +1407,17 @@ function capitalize(str) {
function inViewPort(x, y, win) {
assert.number(x, `Expected x to be finite number`);
assert.number(y, `Expected y to be finite number`);
// Viewport includes scrollbars if rendered.
return !(x < 0 || y < 0 || x > win.innerWidth || y > win.innerHeight);
}
-function getElementCenter(elementReference, seenEls, container) {
+function getElementCenter(elementReference, seenEls, window) {
if (element.isWebElementReference(elementReference)) {
let uuid = elementReference[element.Key] ||
elementReference[element.LegacyKey];
- let el = seenEls.get(uuid, container);
+ let el = seenEls.get(uuid, {frame: window});
return element.coordinates(el);
}
return {};
}