Bug 1637259 - Dispatch touch event for WM_POINTER r=edgar,aklotz
authorKagami Sascha Rosylight <krosylight@mozilla.com>
Wed, 21 Apr 2021 00:13:14 +0000
changeset 576886 3df0f92987d1bba705cbdf8c5fe366b9d3071bc4
parent 576885 a46a3719b9aa862836c247a487a754a9f408424a
child 576887 851ad4f16be31a11de2f1750dde884af81b4934d
push id141600
push userkrosylight@mozilla.com
push dateWed, 21 Apr 2021 00:15:40 +0000
treeherderautoland@3df0f92987d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedgar, aklotz
bugs1637259
milestone90.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1637259 - Dispatch touch event for WM_POINTER r=edgar,aklotz Differential Revision: https://phabricator.services.mozilla.com/D111513
dom/events/PointerEventHandler.cpp
dom/events/test/mochitest.ini
dom/events/test/test_bug1637259.html
modules/libpref/init/StaticPrefList.yaml
testing/mochitest/tests/SimpleTest/EventUtils.js
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/dom/events/PointerEventHandler.cpp
+++ b/dom/events/PointerEventHandler.cpp
@@ -551,16 +551,17 @@ void PointerEventHandler::InitPointerEve
   aPointerEvent->tiltY = aTouch->tiltY;
   aPointerEvent->mTime = aTouchEvent->mTime;
   aPointerEvent->mTimeStamp = aTouchEvent->mTimeStamp;
   aPointerEvent->mFlags = aTouchEvent->mFlags;
   aPointerEvent->mButton = button;
   aPointerEvent->mButtons = buttons;
   aPointerEvent->mInputSource = MouseEvent_Binding::MOZ_SOURCE_TOUCH;
   aPointerEvent->mFromTouchEvent = true;
+  aPointerEvent->mPressure = aTouch->mForce;
 }
 
 /* static */
 void PointerEventHandler::DispatchPointerFromMouseOrTouch(
     PresShell* aShell, nsIFrame* aFrame, nsIContent* aContent,
     WidgetGUIEvent* aEvent, bool aDontRetargetEvents, nsEventStatus* aStatus,
     nsIContent** aTargetContent) {
   MOZ_ASSERT(aFrame || aContent);
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -269,14 +269,19 @@ skip-if = verify
 support-files =
   file_focus_blur_on_click_in_cross_origin_iframe.html
 skip-if = toolkit == 'android' # Bug 1701546
 [test_focus_blur_on_click_in_deep_cross_origin_iframe.html]
 support-files =
   file_focus_blur_on_click_in_deep_cross_origin_iframe_inner.html
   file_focus_blur_on_click_in_deep_cross_origin_iframe_middle.html
 skip-if = toolkit == 'android' # Bug 1701546
+[test_bug1637259.html]
+disabled = Enable this when the taskcluster Windows machine upgrades to RS5+
+run-if = toolkit == 'windows' # Only Windows supports pen input synthesis
+support-files =
+  !/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
 [test_bug1692277.html]
 disabled = Enable this when the taskcluster Windows machine upgrades to RS5+
 run-if = toolkit == 'windows' # Only Windows supports pen input synthesis
 support-files =
   !/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
   !/dom/base/test/Ahem.ttf
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_bug1637259.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Bug 1692277</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+<script src="/tests/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
+
+<style>
+  #container {
+    width: 100px;
+    height: 100px;
+    overflow: scroll;
+  }
+
+  #child {
+    width: 200px;
+    height: 200px;
+  }
+</style>
+
+<div id="container">
+  <div id="child"></div>
+</div>
+
+<script>
+  /**
+   * @template {keyof HTMLElementEventMap} K
+   * @param {HTMLElemnt} target
+   * @param {K} eventName
+   * @return {HTMLElementEventMap[K]}
+   */
+  function waitForEvent(target, eventName) {
+    return new Promise(resolve => {
+      target.addEventListener(eventName, resolve, { once: true });
+    });
+  }
+
+  add_task(async function testPenDrag() {
+    await SpecialPowers.pushPrefEnv({
+      set: [
+        ["dom.w3c_pointer_events.dispatch_by_pointer_messages", true],
+        ["dom.w3c_pointer_events.scroll_by_pen.enabled", true],
+        // Run the font loader task eagerly for more predictable behavior,
+        // see bug 1672141.
+        ["gfx.font_loader.delay", 0],
+        ["gfx.font_loader.interval", 0],
+      ],
+    });
+
+    await SimpleTest.promiseFocus();
+    const container = document.getElementById("container");
+    const scrollPromise = waitForEvent(container, "scroll");
+    const pointerPromise = waitForEvent(container, "pointerdown");
+    await promiseNativePointerDrag(container, "pen", 50, 50, -50, -50);
+    await scrollPromise;
+
+    const pointerdown = await pointerPromise;
+    // is(pointerdown.pointerType, "pen"); // TODO: bug 1706420
+    is(pointerdown.type, "pointerdown", ".type");
+    is(pointerdown.button, 0, ".button");
+    is(pointerdown.buttons, 1, ".buttons");
+    is(pointerdown.layerX, 50, ".layerX");
+    is(pointerdown.layerY, 50, ".layerY");
+    is(pointerdown.pressure, 1, ".pressure");
+    // TODO: tilt etc. (bug 1706420)
+  });
+</script>
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -3492,16 +3492,21 @@
 
 #ifdef XP_WIN
   # Control firing WidgetMouseEvent by handling Windows pointer messages or
   # mouse messages.
 -   name: dom.w3c_pointer_events.dispatch_by_pointer_messages
     type: bool
     value: false
     mirror: always
+
+-   name: dom.w3c_pointer_events.scroll_by_pen.enabled
+    type: bool
+    value: false
+    mirror: always
 #endif
 
 # If the value is >= 0, it will be used for max touch points in child processes.
 - name: dom.maxtouchpoints.testing.value
   type: int32_t
   value: -1
   mirror: always
 
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -627,17 +627,17 @@ function synthesizeTouchAtPoint(left, to
   var utils = _getDOMWindowUtils(aWindow);
   let defaultPrevented = 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 || 1;
+    var force = aEvent.force || (aEvent.type === "touchend" ? 0 : 1);
     var modifiers = _parseModifiers(aEvent, aWindow);
 
     if ("type" in aEvent && aEvent.type) {
       defaultPrevented = utils.sendTouchEvent(
         aEvent.type,
         [id],
         [left],
         [top],
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -8515,16 +8515,57 @@ bool nsWindow::WidgetTypeSupportsAcceler
   //
   // Also see bug 1150376, D3D11 composition can cause issues on some devices
   // on Windows 7 where presentation fails randomly for windows with drop
   // shadows.
   return mTransparencyMode != eTransparencyTransparent &&
          !(IsPopup() && DeviceManagerDx::Get()->IsWARP());
 }
 
+bool nsWindow::DispatchTouchEventFromWMPointer(
+    UINT msg, LPARAM aLParam, const WinPointerInfo& aPointerInfo) {
+  MultiTouchInput::MultiTouchType touchType;
+  switch (msg) {
+    case WM_POINTERDOWN:
+      touchType = MultiTouchInput::MULTITOUCH_START;
+      break;
+    case WM_POINTERUPDATE:
+      if (aPointerInfo.mPressure == 0) {
+        return false;  // hover
+      }
+      touchType = MultiTouchInput::MULTITOUCH_MOVE;
+      break;
+    case WM_POINTERUP:
+      touchType = MultiTouchInput::MULTITOUCH_END;
+      break;
+    default:
+      return false;
+  }
+
+  nsPointWin touchPoint;
+  touchPoint.x = GET_X_LPARAM(aLParam);
+  touchPoint.y = GET_Y_LPARAM(aLParam);
+  touchPoint.ScreenToClient(mWnd);
+
+  SingleTouchData touchData(aPointerInfo.pointerId,
+                            ScreenIntPoint::FromUnknownPoint(touchPoint),
+                            ScreenSize(1, 1),  // pixel size radius for pen
+                            0.0f,              // no radius rotation
+                            aPointerInfo.mPressure);
+
+  MultiTouchInput touchInput;
+  touchInput.mType = touchType;
+  touchInput.mTime = ::GetMessageTime();
+  touchInput.mTimeStamp = GetMessageTimeStamp(touchInput.mTime);
+  touchInput.mTouches.AppendElement(touchData);
+
+  DispatchTouchInput(touchInput);
+  return true;
+}
+
 bool nsWindow::OnPointerEvents(UINT msg, WPARAM aWParam, LPARAM aLParam) {
   if (!mPointerEvents.ShouldHandleWinPointerMessages(msg, aWParam)) {
     return false;
   }
   if (!mPointerEvents.ShouldFirePointerEventByWinPointerMessages()) {
     // We have to handle WM_POINTER* to fetch and cache pen related information
     // and fire WidgetMouseEvent with the cached information the WM_*BUTTONDOWN
     // handler. This is because Windows doesn't support ::DoDragDrop in the
@@ -8592,29 +8633,34 @@ bool nsWindow::OnPointerEvents(UINT msg,
       break;
     case WM_POINTERLEAVE:
       message = eMouseExitFromWidget;
       break;
     default:
       return false;
   }
   uint32_t pointerId = mPointerEvents.GetPointerId(aWParam);
-  POINTER_PEN_INFO penInfo;
+  POINTER_PEN_INFO penInfo{};
   mPointerEvents.GetPointerPenInfo(pointerId, &penInfo);
 
   // Windows defines the pen pressure is normalized to a range between 0 and
   // 1024. Convert it to float.
   float pressure = penInfo.pressure ? (float)penInfo.pressure / 1024 : 0;
   int16_t buttons = sPointerDown ? button == MouseButton::ePrimary
                                        ? MouseButtonsFlag::ePrimaryFlag
                                        : MouseButtonsFlag::eSecondaryFlag
                                  : MouseButtonsFlag::eNoButtons;
   WinPointerInfo pointerInfo(pointerId, penInfo.tiltX, penInfo.tiltY, pressure,
                              buttons);
 
+  if (StaticPrefs::dom_w3c_pointer_events_scroll_by_pen_enabled() &&
+      DispatchTouchEventFromWMPointer(msg, aLParam, pointerInfo)) {
+    return true;
+  }
+
   // The aLParam of WM_POINTER* is the screen location. Convert it to client
   // location
   LPARAM newLParam = lParamToClient(aLParam);
   DispatchMouseEvent(message, aWParam, newLParam, false, button,
                      MouseEvent_Binding::MOZ_SOURCE_PEN, &pointerInfo);
   // Consume WM_POINTER* to stop Windows fires WM_*BUTTONDOWN / WM_*BUTTONUP
   // WM_MOUSEMOVE.
   return true;
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -510,16 +510,19 @@ class nsWindow final : public nsWindowBa
  private:
   void SetWindowTranslucencyInner(nsTransparencyMode aMode);
   nsTransparencyMode GetWindowTranslucencyInner() const {
     return mTransparencyMode;
   }
   void UpdateGlass();
   bool WithinDraggableRegion(int32_t clientX, int32_t clientY);
 
+  bool DispatchTouchEventFromWMPointer(UINT msg, LPARAM aLParam,
+                                       const WinPointerInfo& aPointerInfo);
+
  protected:
 #endif  // MOZ_XUL
 
   static bool IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult);
   void IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam);
 
   /**
    * Misc.