Commit ca736ae4 authored by Masayuki Nakano's avatar Masayuki Nakano Committed by masayuki@d-toybox.com
Browse files

Bug 1966551 - Make `PointerEventHandler::DispatchPointerFromMouseOrTouch()`...

Bug 1966551 - Make `PointerEventHandler::DispatchPointerFromMouseOrTouch()` dispatch synthesized `ePointerMove` for synthesized `eMouseMove` if it's caused by hoverable pointer r=smaug

Currently, we don't dispatch synthesized `ePointerMove` unless it's
required for dispatch the boundary events after dispatching
`ePointerLostCapture` event [1] since Pointer Events defined that the
boundary events should be fired only when before dispatching a pointer
event.  However, it's changed, Point Events currently defines that the
boundary events should be fired if the element under the pointer is
changed without a `pointermove` [2] if and only if the pointer supports
hover.

Therefore, this patch makes `PresShell` store the last input source
whose event set the mouse location at last and
`PresShell::ProcessSynthMouseMoveEvent()` sets the input source to make
`PointerEventHandler::DispatchPointerFromMouseOrTouch()` can consider
whether it needs to dispatch pointer boundary events or not for the
pointer.

Additionally, the mochitests for the manual WPTs under
`dom/events/test/pointerevents` checks `pointerId`.  Therefore, this
patch makes `PresShell` also store the last `pointerId` and set it to
the synthesized `eMouseMove` too.

I think that this approach is **not** correct approach to fix this bug
because there could be multiple hoverable pointers, but we synthesize
pointer boundary events only for the last input device.  I think it's
enough for now because we've not supported pen well (we've not supported
the test API yet!), so, we only support only mouse input well as
hoverable inputs.  I think we should extend `PointerInfo` and make a
synthesizer of `ePointerMove` later.

Note that this patch changes 2 WPTs which both are in the scope of
Interop.

The expectation of
`pointerevent_pointer_boundary_events_after_removing_last_over_element.html`
needs to be changed for conforming to the latest spec.  I wrote this
test before the spec change and it wasn't updated when the spec is
changed. I filed this issue to interop [3].

The changes for `pointerevent_pointerout_no_pointer_movement.html` is
required for avoiding the timeout.  Gecko does not allow recursive
synthesized `eMouseMove` to prevent infinite reflow loops without moving
the mouse cursor.  However, the test expects that and that causes
requiring the hack for Chrome too.  Therefore, I split the test to
make each step run in different event loop and I removed the hack for
Chrome.

Note that this patch also removes 2 sets of mochitests for WPT manual
tests because they are now tested with the test driver [4][5] and they
fail without maintained.

1. https://searchfox.org/mozilla-central/rev/f571db8014431de31d245017e2f5457046aec4ea/dom/events/PointerEventHandler.cpp#494-503
2. https://w3c.github.io/pointerevents/#boundary-events-caused-by-layout-changes
3. https://github.com/web-platform-tests/interop/issues/961
4. https://wpt.fyi/results/pointerevents/pointerevent_boundary_events_in_capturing.html%3Fmouse?label=master&label=experimental&aligned&view=interop
5. https://wpt.fyi/results/pointerevents/pointerevent_releasepointercapture_events_to_original_target.html%3Fmouse?label=master&label=experimental&aligned&view=interop

Differential Revision: https://phabricator.services.mozilla.com/D250421
parent 0c6fc3dd
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -894,12 +894,31 @@ void PointerEventHandler::DispatchPointerFromMouseOrTouch(
      return;
    }

    // 1. If it is not mouse then it is likely will come as touch event
    // 2. We don't synthesize pointer events for synthesized mouse move
    if (!mouseEvent->convertToPointer || mouseEvent->IsSynthesized()) {
    // If it is not mouse then it is likely will come as touch event
    if (!mouseEvent->convertToPointer) {
      return;
    }

    // If it's a synthesized eMouseMove and the input source supports hover, we
    // need to dispatch pointer boundary events if the element underneath the
    // pointer has already been changed from the last `pointerover` event
    // target.
    if (mouseEvent->IsSynthesized()) {
      if (!StaticPrefs::
              dom_event_pointer_boundary_dispatch_when_layout_change() ||
          !mouseEvent->InputSourceSupportsHover()) {
        return;
      }
      // So, if the pointer is captured, we don't need to dispatch pointer
      // boundary events since pointer boundary events should be fired before
      // gotpointercapture.
      PointerCaptureInfo* const captureInfo =
          GetPointerCaptureInfo(mouseEvent->pointerId);
      if (captureInfo && captureInfo->mOverrideElement) {
        return;
      }
    }

    pointerMessage = PointerEventHandler::ToPointerEventMessage(mouseEvent);
    if (pointerMessage == eVoidEvent) {
      return;
+0 −14
Original line number Diff line number Diff line
@@ -144,13 +144,6 @@ skip-if = [
  "http2",
]

["test_wpt_pointerevent_boundary_events_in_capturing-manual.html"]
support-files = ["wpt/pointerevent_boundary_events_in_capturing-manual.html"]
skip-if = [
  "http3",
  "http2",
]

["test_wpt_pointerevent_drag_interaction-manual.html"]
support-files = ["wpt/html/pointerevent_drag_interaction-manual.html"]
skip-if = [
@@ -207,13 +200,6 @@ skip-if = [
  "http2",
]

["test_wpt_pointerevent_releasepointercapture_events_to_original_target-manual.html"]
support-files = ["wpt/pointerevent_releasepointercapture_events_to_original_target-manual.html"]
skip-if = [
  "http3",
  "http2",
]

["test_wpt_pointerevent_releasepointercapture_onpointercancel_touch-manual.html"]
support-files = ["wpt/pointerevent_releasepointercapture_onpointercancel_touch-manual.html"]
skip-if = [
+12 −6
Original line number Diff line number Diff line
@@ -24,16 +24,22 @@ function runTests() {
  let target0 = window.document.getElementById("target0");
  let pointerEventsList = ["pointerover", "pointerenter", "pointerdown",
                           "pointerup", "pointerleave", "pointerout"];
  let receivedPointerEvents = false;
  const pointerEvents = [];
  pointerEventsList.forEach((elem, index, arr) => {
    target0.addEventListener(elem, (event) => {
      ok(false, "receiving event " + event.type);
      receivedPointerEvents = true;
    });
    target0.addEventListener(elem, event => pointerEvents.push(event.type));
  });

  target1.addEventListener("mouseup", () => {
    ok(!receivedPointerEvents, "synthesized mousemove should not trigger any pointer events");
    is(
      pointerEvents.join(", "),
      [
        "pointerover", // Should be caused by the synthesized mousemove
        "pointerenter",
        "pointerout", // Should be caused by clicking target1
        "pointerleave",
      ].join(", "),
      "Synthesizing mousemove should cause only pointer boundary events"
    );
    SimpleTest.finish();
  });

+0 −46
Original line number Diff line number Diff line
<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8">
    <title>W3C pointerevent_boundary_events_in_capturing-manual.html in Mochitest form</title>
    <script src="/tests/SimpleTest/SimpleTest.js"></script>
    <script src="/tests/SimpleTest/EventUtils.js"></script>
    <script type="text/javascript" src="mochitest_support_external.js"></script>
    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
    <script type="text/javascript">
      SimpleTest.waitForExplicitFinish();
      function startTest() {
        runTestInNewWindow("wpt/pointerevent_boundary_events_in_capturing-manual.html", true);
      }
      function executeTest(int_win) {
        sendMouseEvent(int_win, "target0", "mousemove");
        sendMouseEvent(int_win, "target0", "mousedown");
        sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
        sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
        sendMouseEvent(int_win, "target0", "mouseup");

        window.addEventListener("message", function(aEvent) {
          if (aEvent.data == "Test Touch") {
            // Synthesize touch events to run this test.
            sendTouchEvent(int_win, "target0", "touchstart");
            sendTouchEvent(int_win, "target0", "touchmove", {offsetX: 10});
            sendTouchEvent(int_win, "target0", "touchmove", {offsetX: 15});
            sendTouchEvent(int_win, "target0", "touchmove", {offsetX: 20});
            sendTouchEvent(int_win, "target0", "touchend");
            window.postMessage("Test Pen", "*");
          } else if (aEvent.data == "Test Pen") {
            // Synthesize pen events to run this test.
            sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
            sendMouseEvent(int_win, "target0", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
            sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
            sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
            sendMouseEvent(int_win, "target0", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
          }
        });
        window.postMessage("Test Touch", "*");
      }
    </script>
  </head>
  <body>
  </body>
</html>
+0 −49
Original line number Diff line number Diff line
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
-->
  <head>
    <meta charset="utf-8">
    <title>Test for Bug 1000870</title>
    <meta name="author" content="Maksim Lebedev" />
    <script src="/tests/SimpleTest/SimpleTest.js"></script>
    <script src="/tests/SimpleTest/EventUtils.js"></script>
    <script type="text/javascript" src="mochitest_support_external.js"></script>
    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
    <script type="text/javascript">
      SimpleTest.waitForExplicitFinish();
      function startTest() {
        runTestInNewWindow("wpt/pointerevent_releasepointercapture_events_to_original_target-manual.html");
      }
      function executeTest(int_win) {
        // Synthesize mouse events to run this test.
        sendMouseEvent(int_win, "target0", "mousemove");
        sendMouseEvent(int_win, "target0", "mousedown");
        sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
        sendMouseEvent(int_win, "target0", "mousemove", {buttons: 1});
        sendMouseEvent(int_win, "target0", "mouseup");

        window.addEventListener("message", function(aEvent) {
          if (aEvent.data == "Test Touch") {
            // Synthesize touch events to run this test.
            sendTouchEvent(int_win, "target0", "touchstart", {offsetX: 10});
            sendTouchEvent(int_win, "target0", "touchmove", {offsetX: 11});
            sendTouchEvent(int_win, "target0", "touchend", {offsetX: 11});
            window.postMessage("Test Pen", "*");
          } else if (aEvent.data == "Test Pen") {
            // Synthesize pen events to run this test.
            sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
            sendMouseEvent(int_win, "target0", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
            sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
            sendMouseEvent(int_win, "target0", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_PEN, buttons: 1});
            sendMouseEvent(int_win, "target0", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_PEN});
          }
        });
        window.postMessage("Test Touch", "*");
      }
    </script>
  </head>
  <body>
  </body>
</html>
Loading