Commit 293d2541 authored by Masayuki Nakano's avatar Masayuki Nakano
Browse files

Bug 1691622 - part 5: Make `synthesizeNativeMouseClick*` take an event type r=smaug

Let's make `synthesizeNativeMouseClick*` take an event type, and only when
it's click, it should send native mouse event twice.

Then, we can all them `synthesizeNativeMouseEvent*`.

Differential Revision: https://phabricator.services.mozilla.com/D105759
parent b63882dd
Loading
Loading
Loading
Loading
+97 −85
Original line number Diff line number Diff line
@@ -783,32 +783,14 @@ function synthesizeNativeTap(aElement, aX, aY, aObserver = null) {
  return true;
}

function synthesizeNativeMouseEvent(aTarget, aX, aY, aType, aObserver = null) {
  var pt = coordinatesRelativeToScreen({
    offsetX: aX,
    offsetY: aY,
    target: aTarget,
  });
  var utils = utilsForTarget(aTarget);
  var element = elementForTarget(aTarget);
  utils.sendNativeMouseEvent(pt.x, pt.y, aType, 0, element, aObserver);
  return true;
}

// Promise-returning variant of synthesizeNativeMouseEvent
function promiseNativeMouseEvent(aTarget, aX, aY, aType) {
  return new Promise(resolve => {
    synthesizeNativeMouseEvent(aTarget, aX, aY, aType, resolve);
  });
}

function synthesizeNativeMouseClickWithAPZ(aParams, aObserver = null) {
function synthesizeNativeMouseEventWithAPZ(aParams, aObserver = null) {
  if (aParams.win !== undefined) {
    throw Error(
      "Are you trying to use EventUtils' API? `win` won't be used with synthesizeNativeMouseClickWithAPZ."
    );
  }
  const {
    type, // "click", "mousedown", "mouseup" or "mousemove"
    target, // Origin of offsetX and offsetY, must be an element
    offsetX, // X offset in `target`
    offsetY, // Y offset in `target`
@@ -852,35 +834,65 @@ function synthesizeNativeMouseClickWithAPZ(aParams, aObserver = null) {
      target,
    });
  })();
  const utils = SpecialPowers.getDOMWindowUtils(
    target.ownerDocument.defaultView
  );
  const utils = utilsForTarget(target);
  const element = elementForTarget(target);
  const modifierFlags = parseNativeModifiers(modifiers);
  if (type === "click") {
    utils.sendNativeMouseEvent(
      pt.x,
      pt.y,
      nativeMouseDownEventMsg(),
      modifierFlags,
    target,
      element,
      function() {
        utils.sendNativeMouseEvent(
          pt.x,
          pt.y,
          nativeMouseUpEventMsg(),
          modifierFlags,
        target,
          element,
          aObserver
        );
      }
    );
  return true;
    return;
  }

  utils.sendNativeMouseEvent(
    pt.x,
    pt.y,
    (() => {
      switch (type) {
        case "mousedown":
          return nativeMouseDownEventMsg();
        case "mouseup":
          return nativeMouseUpEventMsg();
        case "mousemove":
          return nativeMouseMoveEventMsg();
        default:
          throw Error(`Invalid type is specified: ${type}`);
      }
    })(),
    modifierFlags,
    element,
    aObserver
  );
}

function promiseNativeMouseEventWithAPZ(aParams) {
  return new Promise(resolve =>
    synthesizeNativeMouseEventWithAPZ(aParams, resolve)
  );
}

function synthesizeNativeMouseClickWithAPZ(aParams, aObserver = null) {
  aParams.type = "click";
  return synthesizeNativeMouseEventWithAPZ(aParams, aObserver);
}

// Promise-returning variant of synthesizeNativeMouseClickWithAPZ.
function promiseNativeMouseClickWithAPZ(aParams) {
  return new Promise(resolve => {
    synthesizeNativeMouseClickWithAPZ(aParams, resolve);
  });
  aParams.type = "click";
  return promiseNativeMouseEventWithAPZ(aParams);
}

// See synthesizeNativeMouseClickWithAPZ for the detail of aParams.
@@ -1001,44 +1013,44 @@ async function promiseVerticalScrollbarDrag(
  );

  // Move the mouse to the scrollbar thumb and drag it down
  await promiseNativeMouseEvent(
  await promiseNativeMouseEventWithAPZ({
    target,
    mouseX,
    mouseY,
    nativeMouseMoveEventMsg()
  );
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });
  // mouse down
  await promiseNativeMouseEvent(
  await promiseNativeMouseEventWithAPZ({
    target,
    mouseX,
    mouseY,
    nativeMouseDownEventMsg()
  );
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousedown",
  });
  // drag vertically by |increment| until we reach the specified distance
  for (var y = increment; y < distance; y += increment) {
    await promiseNativeMouseEvent(
    await promiseNativeMouseEventWithAPZ({
      target,
      mouseX,
      mouseY + y,
      nativeMouseMoveEventMsg()
    );
      offsetX: mouseX,
      offsetY: mouseY + y,
      type: "mousemove",
    });
  }
  await promiseNativeMouseEvent(
  await promiseNativeMouseEventWithAPZ({
    target,
    mouseX,
    mouseY + distance,
    nativeMouseMoveEventMsg()
  );
    offsetX: mouseX,
    offsetY: mouseY + distance,
    type: "mousemove",
  });

  // and return an async function to call afterwards to finish up the drag
  return async function() {
    dump("Finishing drag of #" + targetElement.id + "\n");
    await promiseNativeMouseEvent(
    await promiseNativeMouseEventWithAPZ({
      target,
      mouseX,
      mouseY + distance,
      nativeMouseUpEventMsg()
    );
      offsetX: mouseX,
      offsetY: mouseY + distance,
      type: "mouseup",
    });
  };
}

@@ -1074,40 +1086,40 @@ async function promiseNativeMouseDrag(
  );

  // Move the mouse to the target position
  await promiseNativeMouseEvent(
  await promiseNativeMouseEventWithAPZ({
    target,
    mouseX,
    mouseY,
    nativeMouseMoveEventMsg()
  );
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });
  // mouse down
  await promiseNativeMouseEvent(
  await promiseNativeMouseEventWithAPZ({
    target,
    mouseX,
    mouseY,
    nativeMouseDownEventMsg()
  );
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousedown",
  });
  // drag vertically by |increment| until we reach the specified distance
  for (var s = 1; s <= steps; s++) {
    let dx = distanceX * (s / steps);
    let dy = distanceY * (s / steps);
    dump(`Dragging to ${mouseX + dx}, ${mouseY + dy} from target\n`);
    await promiseNativeMouseEvent(
    await promiseNativeMouseEventWithAPZ({
      target,
      mouseX + dx,
      mouseY + dy,
      nativeMouseMoveEventMsg()
    );
      offsetX: mouseX + dx,
      offsetY: mouseY + dy,
      type: "mousemove",
    });
  }

  // and return a function-wrapped promise to call afterwards to finish the drag
  return function() {
    return promiseNativeMouseEvent(
    return promiseNativeMouseEventWithAPZ({
      target,
      mouseX + distanceX,
      mouseY + distanceY,
      nativeMouseUpEventMsg()
    );
      offsetX: mouseX + distanceX,
      offsetY: mouseY + distanceY,
      type: "mouseup",
    });
  };
}

+24 −4
Original line number Diff line number Diff line
@@ -44,15 +44,35 @@ async function test() {

  var scrollbarX = (window.innerWidth + root.clientWidth) / 2;
  // Move the mouse to the scrollbar
  await promiseNativeMouseEvent(root, scrollbarX, 100, nativeMouseMoveEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: root,
    offsetX: scrollbarX,
    offsetY: 100,
    type: "mousemove",
  });
  // mouse down
  await promiseNativeMouseEvent(root, scrollbarX, 100, nativeMouseDownEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: root,
    offsetX: scrollbarX,
    offsetY: 100,
    type: "mousedown",
  });
  // drag vertically
  await promiseNativeMouseEvent(root, scrollbarX, 150, nativeMouseMoveEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: root,
    offsetX: scrollbarX,
    offsetY: 150,
    type: "mousemove",
  });
  // wait for the scroll listener to fire
  await scrollPromise;
  // and release
  await promiseNativeMouseEvent(root, scrollbarX, 150, nativeMouseUpEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: root,
    offsetX: scrollbarX,
    offsetY: 150,
    type: "mouseup",
  });
}

waitUntilApzStable()
+30 −5
Original line number Diff line number Diff line
@@ -15,13 +15,38 @@ async function test() {
  });

  // Ensure the pointer is inside the window
  await promiseNativeMouseEvent(document.getElementById("b"), 5, 5, nativeMouseMoveEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: document.getElementById("b"),
    offsetX: 5,
    offsetY: 5,
    type: "mousemove",
  });
  // mouse down, move it around, and release it near where it went down. this
  // should generate a click at the release point
  await promiseNativeMouseEvent(document.getElementById("b"), 5, 5, nativeMouseDownEventMsg());
  await promiseNativeMouseEvent(document.getElementById("b"), 100, 100, nativeMouseMoveEventMsg());
  await promiseNativeMouseEvent(document.getElementById("b"), 10, 10, nativeMouseMoveEventMsg());
  await promiseNativeMouseEvent(document.getElementById("b"), 8, 8, nativeMouseUpEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: document.getElementById("b"),
    offsetX: 5,
    offsetY: 5,
    type: "mousedown",
  });
  await promiseNativeMouseEventWithAPZ({
    target: document.getElementById("b"),
    offsetX: 100,
    offsetY: 100,
    type: "mousemove",
  });
  await promiseNativeMouseEventWithAPZ({
    target: document.getElementById("b"),
    offsetX: 10,
    offsetY: 10,
    type: "mousemove",
  });
  await promiseNativeMouseEventWithAPZ({
    target: document.getElementById("b"),
    offsetX: 8,
    offsetY: 8,
    type: "mouseup",
  });
  dump("Finished synthesizing click with a drag in the middle\n");

  let e = await clickPromise;
+24 −4
Original line number Diff line number Diff line
@@ -49,7 +49,12 @@ async function downMouseAndHandleEvent(x, y) {
      resolve();
    }, {capture: true, once: true});
  });
  synthesizeNativeMouseEvent(bar, x, y, nativeMouseDownEventMsg());
  synthesizeNativeMouseEventWithAPZ({
    target: bar,
    offsetX: x,
    offsetY: y,
    type: "mousedown",
  });
  await mouseDownHandledPromise;
}

@@ -86,7 +91,12 @@ async function moveMouseAndHandleEvent(x, y) {
    bar.addEventListener("mousemove", mouseOnTarget, true);
    window.addEventListener("mousemove", mouseOffTarget);
  });
  synthesizeNativeMouseEvent(bar, x, y, nativeMouseMoveEventMsg());
  synthesizeNativeMouseEventWithAPZ({
    target: bar,
    offsetX: x,
    offsetY: y,
    type: "mousemove",
  });
  await mouseMoveHandledPromise;
}

@@ -101,7 +111,12 @@ async function test() {
  }, true);

  // Move the mouse to the "scrollbar" (the div upon which dragging changes scroll position)
  await promiseNativeMouseEvent(bar, 10, 10, nativeMouseMoveEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: bar,
    offsetX: 10,
    offsetY: 10,
    type: "mousemove",
   });

  // mouse down
  await downMouseAndHandleEvent(10, 10);
@@ -116,7 +131,12 @@ async function test() {
  await moveMouseAndHandleEvent(10, 360);
  await moveMouseAndHandleEvent(10, 410);
  // and release
  await promiseNativeMouseEvent(bar, 10, 410, nativeMouseUpEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: bar,
    offsetX: 10,
    offsetY: 410,
    type: "mouseup",
   });
}

waitUntilApzStable()
+36 −6
Original line number Diff line number Diff line
@@ -46,11 +46,26 @@ async function test() {
  dump("Starting drag at " + mouseX + ", " + mouseY + " from top-left of #" + scrollableDiv.id + "\n");

  // Move the mouse to the scrollbar thumb and drag it down
  await promiseNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseMoveEventMsg());
  await promiseNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseDownEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousedown",
  });
  // drag down by 100 pixels
  mouseY += 100;
  await promiseNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseMoveEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });

  // wait here until the scroll event listener is triggered.
  await scrollPromise;
@@ -68,7 +83,12 @@ async function test() {
  });
  // Add 2 to snapMultipler just to make sure we get far enough away from the scrollbar
  var snapBackDistance = (snapMultiplier + 2) * verticalScrollbarWidth;
  await promiseNativeMouseEvent(scrollableDiv, mouseX + snapBackDistance, mouseY + 10, nativeMouseMoveEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX + snapBackDistance,
    offsetY: mouseY + 10,
    type: "mousemove",
  });

  // wait here until the scroll happens
  await scrollPromise;
@@ -83,14 +103,24 @@ async function test() {
  scrollPromise = new Promise(resolve => {
    scrollableDiv.addEventListener("scroll", resolve, {once: true});
  });
  await promiseNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseMoveEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mousemove",
  });

  // wait here until the scroll happens
  await scrollPromise;
  ok(scrollableDiv.scrollTop == savedScrollPos, "Scroll position was restored to " + scrollableDiv.scrollTop);

  // Release mouse and ensure the scroll position stuck
  await promiseNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseUpEventMsg());
  await promiseNativeMouseEventWithAPZ({
    target: scrollableDiv,
    offsetX: mouseX,
    offsetY: mouseY,
    type: "mouseup",
  });
  // Flush everything just to be safe
  await promiseApzRepaintsFlushed();

Loading