⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 246103 in webkit


Ignore:
Timestamp:
Jun 5, 2019, 1:41:30 AM (7 years ago)
Author:
graouts@webkit.org
Message:

[Pointer Events] Add support for chorded button interactions
https://bugs.webkit.org/show_bug.cgi?id=198462

Reviewed by Dean Jackson.

LayoutTests/imported/w3c:

Mark the progression for web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover.html which
proves the correct implementation of the chorded button interactions section of the Pointer Events spec. To do that,
we also had to make use of the "button" parameter used in WPT tests action sequences, which allows the test to indicate
which mouse button is pressed. Finally, there is now a change in the pointerevent_pointermove_on_chorded_mouse_button.html
results, another source change is required to get this test to fully pass.

  • web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
  • web-platform-tests/pointerevents/pointerevent_pointermove_on_chorded_mouse_button-expected.txt:
  • web-platform-tests/resources/testdriver-vendor.js:

(dispatchMouseActions):

Source/WebCore:

Pointer events differ from mouse events in that pressing a button on a mouse and then pressing a second button
would yield two "mousedown" events but a single "pointerdown" event, for the first time we're transitioning from
a state where no button is pressed at all, and then a "pointermove" event to indicate an additional button has been
pressed. This is what the Pointer Events specification calls "chorded button interactions".
See https://w3c.github.io/pointerevents/#chorded-button-interactions for the full details.

To implement this, we no longer directly call PointerEvent::create() from Element::dispatchMouseEvent() but instead
call the new PointerCaptureController::pointerEventForMouseEvent() which implements the required logic to determine
for "mousedown" and "mouseup" mouse events, if we're transitioning from or to a state where no button is pressed at
all.

While that basic change is pretty small, a wider change was required to report the correct value for a PointerEvents'
"button" property which should return "-1" when there is no change in pressed button state compared to any previous
pointer event.

Up until now, MouseEvent.button was an "unsigned short", as specified up to and including DOM Level 2 Events. But the
UI Events spec says that property is a "short", and PointerEvent is the only interface where a "-1" value is used. This
required some changes throughout our codebase since we used a "-1" value to specify that no button was pressed when dealing
with NSEvent input and going through PlatformMouseEvent and eventually MouseEvent. So now we change the various NoButton
enum values to be "-2" and use that value, which is not going to be used for any mouse button, as the value reflected as
"0" through MouseEvent.button, as specified by UI Events.

Furthermore, we identified another issue: MouseEvent.buttons would always return 0 in DRT and WKTR. We rely upon that
value in PointerCaptureController::pointerEventForMouseEvent() and so we had to make that work for the relevant WPT test,
web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover.html, to pass and show a correct implementation
of chorded button interactions. The details of the work required for this is in Tools/ChangeLog.

  • dom/Element.cpp:

(WebCore::Element::dispatchMouseEvent):

  • dom/MouseEvent.cpp:

(WebCore::MouseEvent::create):
(WebCore::MouseEvent::MouseEvent):
(WebCore::MouseEvent::initMouseEvent):
(WebCore::MouseEvent::initMouseEventQuirk):

  • dom/MouseEvent.h:

(WebCore::MouseEvent::button const):

  • dom/MouseEvent.idl:
  • dom/MouseEventInit.h:
  • dom/MouseEventInit.idl:
  • dom/PointerEvent.cpp:

(WebCore::PointerEvent::create):
(WebCore::PointerEvent::PointerEvent):

  • dom/PointerEvent.h:
  • loader/NavigationAction.h:
  • page/PointerCaptureController.cpp:

(WebCore::PointerCaptureController::pointerEventForMouseEvent):

  • page/PointerCaptureController.h:
  • platform/PlatformMouseEvent.h:

Source/WebKit:

Update to use -2 instead of -1 for NoButton.

  • Shared/API/c/WKEvent.h:
  • Shared/WebEvent.h:

Source/WebKitLegacy/mac:

Update -[DOMMouseEvent button] to be a "short" and update the noButton value from -1 to -2.

  • DOM/DOMMouseEvent.h:
  • DOM/DOMMouseEvent.mm:

(-[DOMMouseEvent button]):

  • WebView/WebPDFView.mm:

(-[WebPDFView PDFViewWillClickOnLink:withURL:]):

Tools:

Until now, MouseEvent.buttons would always return 0 when used within DRT and WKTR as [NSEvent pressedMouseButtons], used
by PlatformMouseEventBuilder to set the m_buttons value eventually used to set MouseEvent.buttons, not account for the
NSEvent created through the eventSender JS object in tests. To fix this, we now track the pressed mouse buttons within
DRT and WKTR as mouseDown() and mouseUp() are called, and swizzle [NSEvent pressedMouseButtons] to return that value.

In the case of DRT, one test would fail when swizzling this method in the case where the target view for the event would
be the DRTMockScroller, a subclass of NSScroller. So we only swizzle when the target view is *not* an NSScroller or a
subclass.

Finally, we change the NoMouseButton enum value from -1 to -2 to adjust to MouseEvent.button now being a "short".

  • DumpRenderTree/mac/EventSendingController.mm:

(swizzledEventPressedMouseButtons):
(-[EventSendingController mouseDown:withModifiers:]):
(-[EventSendingController mouseUp:withModifiers:]):
(-[EventSendingController mouseMoveToX:Y:]):

  • TestWebKitAPI/Tests/mac/IsNavigationActionTrusted.mm:
  • WebKitTestRunner/EventSenderProxy.h:

(WTR::EventSenderProxy::mouseButtonsCurrentlyDown const):

  • WebKitTestRunner/mac/EventSenderProxy.mm:

(WTR::swizzledEventPressedMouseButtons):
(WTR::EventSenderProxy::mouseDown):
(WTR::EventSenderProxy::mouseUp):
(WTR::EventSenderProxy::mouseMoveTo):

LayoutTests:

Update some tests and their expectations due to MouseEvent.buttons now returning the correct value in DRT and WKTR
and MouseEvent.button now being a "short" instead of an "unsigned short".

  • fast/events/constructors/mouse-event-constructor-expected.txt:
  • fast/events/constructors/mouse-event-constructor.html: Update the test to test the boundary values for "short" instead

of "unsigned short" as well as the new "magic" value of -2 for no button, which ends up being reported as 0.

  • fast/events/constructors/wheel-event-constructor-expected.txt:
  • fast/events/constructors/wheel-event-constructor.html: Update the test to test the boundary values for "short" instead

of "unsigned short" as well as the new "magic" value of -2 for no button, which ends up being reported as 0.

  • fast/events/fire-mousedown-while-pressing-mouse-button.html: Rewrite this test to always use MouseEvent.buttons and

adjust the bitmask expectations which were way off.

  • platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
  • platform/mac-highsierra/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
  • platform/mac-highsierra-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:

This test fails differently in WK1 and WK2 and will be addressed in a future patch.

Location:
trunk
Files:
5 added
36 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r246096 r246103  
     12019-06-01  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] Add support for chorded button interactions
     4        https://bugs.webkit.org/show_bug.cgi?id=198462
     5
     6        Reviewed by Dean Jackson.
     7
     8        Update some tests and their expectations due to MouseEvent.buttons now returning the correct value in DRT and WKTR
     9        and MouseEvent.button now being a "short" instead of an "unsigned short".
     10
     11        * fast/events/constructors/mouse-event-constructor-expected.txt:
     12        * fast/events/constructors/mouse-event-constructor.html: Update the test to test the boundary values for "short" instead
     13        of "unsigned short" as well as the new "magic" value of -2 for no button, which ends up being reported as 0.
     14        * fast/events/constructors/wheel-event-constructor-expected.txt:
     15        * fast/events/constructors/wheel-event-constructor.html: Update the test to test the boundary values for "short" instead
     16        of "unsigned short" as well as the new "magic" value of -2 for no button, which ends up being reported as 0.
     17        * fast/events/fire-mousedown-while-pressing-mouse-button.html: Rewrite this test to always use MouseEvent.buttons and
     18        adjust the bitmask expectations which were way off.
     19        * platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
     20        * platform/mac-highsierra/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
     21        * platform/mac-highsierra-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
     22        This test fails differently in WK1 and WK2 and will be addressed in a future patch.
     23
    1242019-06-04  Zalan Bujtas  <zalan@apple.com>
    225
  • trunk/LayoutTests/fast/events/constructors/mouse-event-constructor-expected.txt

    r231549 r246103  
    152152PASS new MouseEvent('eventType', { metaKey: true }).metaKey is true
    153153PASS new MouseEvent('eventType', { button: 0 }).button is 0
     154PASS new MouseEvent('eventType', { button: -1 }).button is -1
     155PASS new MouseEvent('eventType', { button: -2 }).button is 0
    154156PASS new MouseEvent('eventType', { button: 1 }).button is 1
    155 PASS new MouseEvent('eventType', { button: 65534 }).button is 65534
    156 PASS new MouseEvent('eventType', { button: 65535 }).button is 0
    157 PASS new MouseEvent('eventType', { button: 9007199254740991 }).button is 0
    158 PASS new MouseEvent('eventType', { button: -1 }).button is 0
     157PASS new MouseEvent('eventType', { button: -32768 }).button is -32768
     158PASS new MouseEvent('eventType', { button: 32767 }).button is 32767
     159PASS new MouseEvent('eventType', { button: 32768 }).button is -32768
     160PASS new MouseEvent('eventType', { button: -32769 }).button is 32767
    159161PASS new MouseEvent('eventType', { button: 18446744073709551615 }).button is 0
    160162PASS new MouseEvent('eventType', { button: 12345678901234567890 }).button is 2048
  • trunk/LayoutTests/fast/events/constructors/mouse-event-constructor.html

    r231549 r246103  
    101101
    102102// button is passed.
    103 // Numbers within the unsigned short range.
     103// Numbers within the short range.
    104104shouldBe("new MouseEvent('eventType', { button: 0 }).button", "0");
     105shouldBe("new MouseEvent('eventType', { button: -1 }).button", "-1");
     106shouldBe("new MouseEvent('eventType', { button: -2 }).button", "0");
    105107shouldBe("new MouseEvent('eventType', { button: 1 }).button", "1");
    106 shouldBe("new MouseEvent('eventType', { button: 65534 }).button", "65534");
    107 
    108 // Numbers that are equal to ((unsigned short)-1) should be treated as 0.
    109 shouldBe("new MouseEvent('eventType', { button: 65535 }).button", "0");
    110 shouldBe("new MouseEvent('eventType', { button: 9007199254740991 }).button", "0");
    111 shouldBe("new MouseEvent('eventType', { button: -1 }).button", "0");
     108shouldBe("new MouseEvent('eventType', { button: -32768 }).button", "-32768");
     109shouldBe("new MouseEvent('eventType', { button: 32767 }).button", "32767");
     110shouldBe("new MouseEvent('eventType', { button: 32768 }).button", "-32768");
     111shouldBe("new MouseEvent('eventType', { button: -32769 }).button", "32767");
    112112
    113113// Numbers out of the unsigned short range.
  • trunk/LayoutTests/fast/events/constructors/wheel-event-constructor-expected.txt

    r231549 r246103  
    222222PASS new WheelEvent('eventType', { metaKey: true }).metaKey is true
    223223PASS new WheelEvent('eventType', { button: 0 }).button is 0
     224PASS new WheelEvent('eventType', { button: -1 }).button is -1
     225PASS new WheelEvent('eventType', { button: -2 }).button is 0
    224226PASS new WheelEvent('eventType', { button: 1 }).button is 1
    225 PASS new WheelEvent('eventType', { button: 65534 }).button is 65534
    226 PASS new WheelEvent('eventType', { button: 65535 }).button is 0
    227 PASS new WheelEvent('eventType', { button: 9007199254740991 }).button is 0
    228 PASS new WheelEvent('eventType', { button: -1 }).button is 0
     227PASS new WheelEvent('eventType', { button: -32768 }).button is -32768
     228PASS new WheelEvent('eventType', { button: 32767 }).button is 32767
     229PASS new WheelEvent('eventType', { button: 32768 }).button is -32768
     230PASS new WheelEvent('eventType', { button: -32769 }).button is 32767
    229231PASS new WheelEvent('eventType', { button: 18446744073709551615 }).button is 0
    230232PASS new WheelEvent('eventType', { button: 12345678901234567890 }).button is 2048
  • trunk/LayoutTests/fast/events/constructors/wheel-event-constructor.html

    r231549 r246103  
    138138
    139139// button is passed.
    140 // Numbers within the unsigned short range.
     140// Numbers within the short range.
    141141shouldBe("new WheelEvent('eventType', { button: 0 }).button", "0");
     142shouldBe("new WheelEvent('eventType', { button: -1 }).button", "-1");
     143shouldBe("new WheelEvent('eventType', { button: -2 }).button", "0");
    142144shouldBe("new WheelEvent('eventType', { button: 1 }).button", "1");
    143 shouldBe("new WheelEvent('eventType', { button: 65534 }).button", "65534");
    144 
    145 // Numbers that are equal to ((unsigned short)-1) should be treated as 0.
    146 shouldBe("new WheelEvent('eventType', { button: 65535 }).button", "0");
    147 shouldBe("new WheelEvent('eventType', { button: 9007199254740991 }).button", "0");
    148 shouldBe("new WheelEvent('eventType', { button: -1 }).button", "0");
     145shouldBe("new WheelEvent('eventType', { button: -32768 }).button", "-32768");
     146shouldBe("new WheelEvent('eventType', { button: 32767 }).button", "32767");
     147shouldBe("new WheelEvent('eventType', { button: 32768 }).button", "-32768");
     148shouldBe("new WheelEvent('eventType', { button: -32769 }).button", "32767");
    149149
    150150// Numbers out of the unsigned short range.
  • trunk/LayoutTests/fast/events/fire-mousedown-while-pressing-mouse-button.html

    r155267 r246103  
    4848}
    4949
    50 function toIEMouseButton(w3cButton)
     50function toBitmaskMouseButton(w3cButton)
    5151{
    5252    switch (w3cButton) {
    5353    case LeftMouseButton:
    54         return 1;
     54        return 1 << 0;
    5555    case MiddleMouseButton:
    56         return 4;
     56        return 1 << 1;
    5757    case RightMouseButton:
    58         return 2;
     58        return 1 << 2;
    5959    }
    6060    return; // We shouldn't get here.
     
    9292function checkIfDoneOnMouseDown(event)
    9393{
    94     var pressedButtons; // A bitmask that represents the combination of buttons that are currently being pressed.
    95     if (event && event.buttons)
    96         pressedButtons = event.buttons; // DOM Level 3 Events (Working Draft 07 September 2010).
    97     else if (event) {
    98         // For browsers than don't support event.buttons (or IE's window.event.button) we convert event.button to
    99         // the corresponding bitmask to simplify the logic below.
    100         pressedButtons = toIEMouseButton(event.button);
    101     } else {
    102         // Assume this script is running within Internet Explorer.
    103         pressedButtons = window.event.button;
    104     }
    105 
     94    var pressedButtons = event.buttons; // A bitmask that represents the combination of buttons that are currently being pressed.
    10695    var chosenFirstMouseButton = firstMouseButtonElem.selectedIndex;
    10796    var chosenSecondMouseButton = secondMouseButtonElem.selectedIndex;
    108     if (!didFireMousedownForFirstMouseButton && (pressedButtons & toIEMouseButton(chosenFirstMouseButton)) == toIEMouseButton(chosenFirstMouseButton)) {
     97    if (!didFireMousedownForFirstMouseButton && (pressedButtons & toBitmaskMouseButton(chosenFirstMouseButton)) == toBitmaskMouseButton(chosenFirstMouseButton)) {
    10998        didFireMousedownForFirstMouseButton = true;
    11099        square.innerHTML = "Now, " + shortMouseButtonName(chosenSecondMouseButton) + " click";
    111     } else if (didFireMousedownForFirstMouseButton && (pressedButtons & toIEMouseButton(chosenSecondMouseButton)) == toIEMouseButton(chosenSecondMouseButton))
     100    } else if (didFireMousedownForFirstMouseButton && (pressedButtons & toBitmaskMouseButton(chosenSecondMouseButton)) == toBitmaskMouseButton(chosenSecondMouseButton))
    112101        didFireMousedownForSecondMouseButton = true;
    113102    if (didFireMousedownForFirstMouseButton && didFireMousedownForSecondMouseButton) {
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r246074 r246103  
     12019-06-01  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] Add support for chorded button interactions
     4        https://bugs.webkit.org/show_bug.cgi?id=198462
     5
     6        Reviewed by Dean Jackson.
     7
     8        Mark the progression for web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover.html which
     9        proves the correct implementation of the chorded button interactions section of the Pointer Events spec. To do that,
     10        we also had to make use of the "button" parameter used in WPT tests action sequences, which allows the test to indicate
     11        which mouse button is pressed. Finally, there is now a change in the pointerevent_pointermove_on_chorded_mouse_button.html
     12        results, another source change is required to get this test to fully pass.
     13
     14        * web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
     15        * web-platform-tests/pointerevents/pointerevent_pointermove_on_chorded_mouse_button-expected.txt:
     16        * web-platform-tests/resources/testdriver-vendor.js:
     17        (dispatchMouseActions):
     18
    1192019-06-04  Antoine Quint  <graouts@apple.com>
    220
  • trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt

    r244393 r246103  
    11
    22FAIL Mouse down and capture to green. assert_array_equals: Received events: green received pointerover,green received pointerenter,green received pointermove,green received pointerdown,green received gotpointercapture,green received pointermove,green received pointerout,green received pointerleave,green received pointerover,green received pointerenter,green received pointermove lengths differ, expected 7 got 11
    3 FAIL Mouse down at green and capture to blue. assert_array_equals: Received events: green received pointerout,green received pointerover,green received pointerenter,green received pointermove,green received pointerdown,green received lostpointercapture,blue received gotpointercapture,blue received pointermove,blue received pointermove lengths differ, expected 11 got 9
    4 FAIL Mouse down and capture to green, move to blue and release capture assert_array_equals: Received events: blue received pointerout,blue received pointerover,blue received pointerenter,blue received pointermove,blue received pointerdown,blue received pointerout,blue received pointerleave,blue received pointerover,blue received pointerenter,blue received pointermove,blue received pointermove lengths differ, expected 12 got 11
     3FAIL Mouse down at green and capture to blue. assert_array_equals: Received events: green received pointerout,green received pointerover,green received pointerenter,green received pointermove,green received pointermove,green received pointermove lengths differ, expected 11 got 6
     4FAIL Mouse down and capture to green, move to blue and release capture assert_array_equals: Received events: green received pointerout,green received pointerover,green received pointerenter,green received pointermove,green received lostpointercapture,green received pointerout,green received pointerleave,blue received pointerover,blue received pointerenter,blue received pointermove,blue received pointermove lengths differ, expected 12 got 11
    55
  • trunk/LayoutTests/imported/w3c/web-platform-tests/pointerevents/pointerevent_pointermove_on_chorded_mouse_button-expected.txt

    r244393 r246103  
    1515
    1616
    17 FAIL pointermove events received for button state changes assert_true: There must not be more than one pointer down event. expected true got false
     17PASS pointermove events received for button state changes
    1818
  • trunk/LayoutTests/imported/w3c/web-platform-tests/resources/testdriver-vendor.js

    r245639 r246103  
    2929                    break;
    3030                case "pointerDown":
    31                     // FIXME: what to do with "button"?
    3231                    logDebug(() => `eventSender.mouseDown()`);
    33                     eventSender.mouseDown();
     32                    eventSender.mouseDown(action.button);
    3433                    break;
    3534                case "pointerUp":
    36                     // FIXME: what to do with "button"?
    3735                    logDebug(() => `eventSender.mouseUp()`);
    38                     eventSender.mouseUp();
     36                    eventSender.mouseUp(action.button);
    3937                    break;
    4038                default:
  • trunk/LayoutTests/platform/mac-highsierra-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt

    r246102 r246103  
    11
    22FAIL Mouse down and capture to green. assert_array_equals: Received events: green received pointerover,green received pointerenter,green received pointermove,green received pointerdown,green received gotpointercapture lengths differ, expected 7 got 5
    3 FAIL Mouse down at green and capture to blue. assert_array_equals: Received events: green received pointerdown,green received lostpointercapture,blue received gotpointercapture lengths differ, expected 11 got 3
    4 FAIL Mouse down and capture to green, move to blue and release capture assert_array_equals: Received events: blue received pointerdown lengths differ, expected 12 got 1
     3FAIL Mouse down at green and capture to blue. assert_array_equals: Received events: green received pointermove lengths differ, expected 11 got 1
     4FAIL Mouse down and capture to green, move to blue and release capture assert_array_equals: Received events: green received pointermove,green received lostpointercapture lengths differ, expected 12 got 2
    55
  • trunk/LayoutTests/platform/mac-highsierra/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt

    r246102 r246103  
    11
    22FAIL Mouse down and capture to green. assert_array_equals: Received events: green received pointerover,green received pointerenter,green received pointermove,green received pointerdown,green received gotpointercapture,green received pointermove,green received pointerout,green received pointerleave,green received pointerover,green received pointerenter,green received pointermove lengths differ, expected 7 got 11
    3 FAIL Mouse down at green and capture to blue. assert_array_equals: Received events: green received pointerout,green received pointerover,green received pointerenter,green received pointermove,green received pointerdown,green received lostpointercapture,blue received gotpointercapture,blue received pointermove,blue received pointermove lengths differ, expected 11 got 9
    4 FAIL Mouse down and capture to green, move to blue and release capture assert_array_equals: Received events: blue received pointerout,blue received pointerover,blue received pointerenter,blue received pointermove,blue received pointerdown,blue received pointerout,blue received pointerleave,blue received pointerover,blue received pointerenter,blue received pointermove,blue received pointermove lengths differ, expected 12 got 11
     3FAIL Mouse down at green and capture to blue. assert_array_equals: Received events: green received pointerout,green received pointerover,green received pointerenter,green received pointermove,green received pointermove,green received pointermove,green received pointermove lengths differ, expected 11 got 7
     4FAIL Mouse down and capture to green, move to blue and release capture assert_array_equals: Received events: green received pointerout,green received pointerover,green received pointerenter,green received pointermove,green received lostpointercapture,green received pointermove,green received pointerout,green received pointerleave,blue received pointerover,blue received pointerenter,blue received pointermove,blue received pointermove property 0, expected "green received pointerover" but got "green received pointerout"
    55
  • trunk/LayoutTests/platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt

    r244393 r246103  
    11
    22FAIL Mouse down and capture to green. assert_array_equals: Received events: green received pointerover,green received pointerenter,green received pointermove,green received pointerdown,green received gotpointercapture lengths differ, expected 7 got 5
    3 FAIL Mouse down at green and capture to blue. assert_array_equals: Received events: green received pointerdown,green received lostpointercapture,blue received gotpointercapture lengths differ, expected 11 got 3
    4 FAIL Mouse down and capture to green, move to blue and release capture assert_array_equals: Received events: blue received pointerdown lengths differ, expected 12 got 1
     3FAIL Mouse down at green and capture to blue. assert_array_equals: Received events:  lengths differ, expected 11 got 0
     4FAIL Mouse down and capture to green, move to blue and release capture assert_array_equals: Received events:  lengths differ, expected 12 got 0
    55
  • trunk/Source/WebCore/ChangeLog

    r246102 r246103  
     12019-06-01  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] Add support for chorded button interactions
     4        https://bugs.webkit.org/show_bug.cgi?id=198462
     5
     6        Reviewed by Dean Jackson.
     7
     8        Pointer events differ from mouse events in that pressing a button on a mouse and then pressing a second button
     9        would yield two "mousedown" events but a single "pointerdown" event, for the first time we're transitioning from
     10        a state where no button is pressed at all, and then a "pointermove" event to indicate an additional button has been
     11        pressed. This is what the Pointer Events specification calls "chorded button interactions".
     12        See https://w3c.github.io/pointerevents/#chorded-button-interactions for the full details.
     13
     14        To implement this, we no longer directly call PointerEvent::create() from Element::dispatchMouseEvent() but instead
     15        call the new PointerCaptureController::pointerEventForMouseEvent() which implements the required logic to determine
     16        for "mousedown" and "mouseup" mouse events, if we're transitioning from or to a state where no button is pressed at
     17        all.
     18
     19        While that basic change is pretty small, a wider change was required to report the correct value for a PointerEvents'
     20        "button" property which should return "-1" when there is no change in pressed button state compared to any previous
     21        pointer event.
     22
     23        Up until now, MouseEvent.button was an "unsigned short", as specified up to and including DOM Level 2 Events. But the
     24        UI Events spec says that property is a "short", and PointerEvent is the only interface where a "-1" value is used. This
     25        required some changes throughout our codebase since we used a "-1" value to specify that no button was pressed when dealing
     26        with NSEvent input and going through PlatformMouseEvent and eventually MouseEvent. So now we change the various NoButton
     27        enum values to be "-2" and use that value, which is not going to be used for any mouse button, as the value reflected as
     28        "0" through MouseEvent.button, as specified by UI Events.
     29
     30        Furthermore, we identified another issue: MouseEvent.buttons would always return 0 in DRT and WKTR. We rely upon that
     31        value in PointerCaptureController::pointerEventForMouseEvent() and so we had to make that work for the relevant WPT test,
     32        web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover.html, to pass and show a correct implementation
     33        of chorded button interactions. The details of the work required for this is in Tools/ChangeLog.
     34
     35        * dom/Element.cpp:
     36        (WebCore::Element::dispatchMouseEvent):
     37        * dom/MouseEvent.cpp:
     38        (WebCore::MouseEvent::create):
     39        (WebCore::MouseEvent::MouseEvent):
     40        (WebCore::MouseEvent::initMouseEvent):
     41        (WebCore::MouseEvent::initMouseEventQuirk):
     42        * dom/MouseEvent.h:
     43        (WebCore::MouseEvent::button const):
     44        * dom/MouseEvent.idl:
     45        * dom/MouseEventInit.h:
     46        * dom/MouseEventInit.idl:
     47        * dom/PointerEvent.cpp:
     48        (WebCore::PointerEvent::create):
     49        (WebCore::PointerEvent::PointerEvent):
     50        * dom/PointerEvent.h:
     51        * loader/NavigationAction.h:
     52        * page/PointerCaptureController.cpp:
     53        (WebCore::PointerCaptureController::pointerEventForMouseEvent):
     54        * page/PointerCaptureController.h:
     55        * platform/PlatformMouseEvent.h:
     56
    1572019-06-05  Michael Catanzaro  <mcatanzaro@igalia.com>
    258
  • trunk/Source/WebCore/dom/Element.cpp

    r245700 r246103  
    315315#if ENABLE(POINTER_EVENTS)
    316316    if (RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled()) {
     317        if (auto* page = document().page()) {
     318            auto& pointerCaptureController = page->pointerCaptureController();
    317319#if ENABLE(TOUCH_EVENTS)
    318         if (auto* page = document().page()) {
    319             if (mouseEvent->type() != eventNames().clickEvent && page->pointerCaptureController().preventsCompatibilityMouseEventsForIdentifier(platformEvent.pointerId()))
     320            if (mouseEvent->type() != eventNames().clickEvent && pointerCaptureController.preventsCompatibilityMouseEventsForIdentifier(platformEvent.pointerId()))
    320321                return false;
     322#else
     323            if (auto pointerEvent = pointerCaptureController.pointerEventForMouseEvent(mouseEvent)) {
     324                pointerCaptureController.dispatchEvent(*pointerEvent, this);
     325                if (isCompatibilityMouseEvent(mouseEvent) && pointerCaptureController.preventsCompatibilityMouseEventsForIdentifier(pointerEvent->pointerId()))
     326                    return false;
     327                if (pointerEvent->defaultPrevented() || pointerEvent->defaultHandled()) {
     328                    didNotSwallowEvent = false;
     329                    if (pointerEvent->type() == eventNames().pointerdownEvent)
     330                        return false;
     331                }
     332            }
     333#endif
    321334        }
    322 #else
    323         if (auto pointerEvent = PointerEvent::create(mouseEvent)) {
    324             if (auto* page = document().page()) {
    325                 page->pointerCaptureController().dispatchEvent(*pointerEvent, this);
    326                 if (isCompatibilityMouseEvent(mouseEvent) && page->pointerCaptureController().preventsCompatibilityMouseEventsForIdentifier(pointerEvent->pointerId()))
    327                     return false;
    328             }
    329             if (pointerEvent->defaultPrevented() || pointerEvent->defaultHandled()) {
    330                 didNotSwallowEvent = false;
    331                 if (pointerEvent->type() == eventNames().pointerdownEvent)
    332                     return false;
    333             }
    334         }
    335 #endif
    336335    }
    337336#endif
  • trunk/Source/WebCore/dom/MouseEvent.cpp

    r235865 r246103  
    6363
    6464Ref<MouseEvent> MouseEvent::create(const AtomicString& type, CanBubble canBubble, IsCancelable isCancelable, IsComposed isComposed, MonotonicTime timestamp, RefPtr<WindowProxy>&& view, int detail,
    65     const IntPoint& screenLocation, const IntPoint& windowLocation, const IntPoint& movementDelta, OptionSet<Modifier> modifiers, unsigned short button, unsigned short buttons,
     65    const IntPoint& screenLocation, const IntPoint& windowLocation, const IntPoint& movementDelta, OptionSet<Modifier> modifiers, short button, unsigned short buttons,
    6666    EventTarget* relatedTarget, double force, unsigned short syntheticClickType, DataTransfer* dataTransfer, IsSimulated isSimulated, IsTrusted isTrusted)
    6767{
     
    7171
    7272Ref<MouseEvent> MouseEvent::create(const AtomicString& eventType, CanBubble canBubble, IsCancelable isCancelable, IsComposed isComposed, RefPtr<WindowProxy>&& view, int detail,
    73     int screenX, int screenY, int clientX, int clientY, OptionSet<Modifier> modifiers, unsigned short button, unsigned short buttons,
     73    int screenX, int screenY, int clientX, int clientY, OptionSet<Modifier> modifiers, short button, unsigned short buttons,
    7474    unsigned short syntheticClickType, EventTarget* relatedTarget)
    7575{
     
    8181MouseEvent::MouseEvent(const AtomicString& eventType, CanBubble canBubble, IsCancelable isCancelable, IsComposed isComposed,
    8282    MonotonicTime timestamp, RefPtr<WindowProxy>&& view, int detail,
    83     const IntPoint& screenLocation, const IntPoint& windowLocation, const IntPoint& movementDelta, OptionSet<Modifier> modifiers, unsigned short button, unsigned short buttons,
     83    const IntPoint& screenLocation, const IntPoint& windowLocation, const IntPoint& movementDelta, OptionSet<Modifier> modifiers, short button, unsigned short buttons,
    8484    EventTarget* relatedTarget, double force, unsigned short syntheticClickType, DataTransfer* dataTransfer, IsSimulated isSimulated, IsTrusted isTrusted)
    8585    : MouseRelatedEvent(eventType, canBubble, isCancelable, isComposed, timestamp, WTFMove(view), detail, screenLocation, windowLocation, movementDelta, modifiers, isSimulated, isTrusted)
    86     , m_button(button == (unsigned short)-1 ? 0 : button)
     86    , m_button(button == -2 ? 0 : button)
    8787    , m_buttons(buttons)
    88     , m_syntheticClickType(button == (unsigned short)-1 ? 0 : syntheticClickType)
    89     , m_buttonDown(button != (unsigned short)-1)
     88    , m_syntheticClickType(button == -2 ? 0 : syntheticClickType)
     89    , m_buttonDown(button != -2)
    9090    , m_relatedTarget(relatedTarget)
    9191    , m_force(force)
     
    9696MouseEvent::MouseEvent(const AtomicString& eventType, CanBubble canBubble, IsCancelable isCancelable, IsComposed isComposed,
    9797    RefPtr<WindowProxy>&& view, int detail, const IntPoint& screenLocation, const IntPoint& clientLocation,
    98     OptionSet<Modifier> modifiers, unsigned short button, unsigned short buttons, unsigned short syntheticClickType, EventTarget* relatedTarget)
     98    OptionSet<Modifier> modifiers, short button, unsigned short buttons, unsigned short syntheticClickType, EventTarget* relatedTarget)
    9999    : MouseRelatedEvent(eventType, canBubble, isCancelable, isComposed, MonotonicTime::now(), WTFMove(view), detail, screenLocation, { }, { }, modifiers, IsSimulated::No)
    100     , m_button(button == (unsigned short)-1 ? 0 : button)
     100    , m_button(button == -2 ? 0 : button)
    101101    , m_buttons(buttons)
    102     , m_syntheticClickType(button == (unsigned short)-1 ? 0 : syntheticClickType)
    103     , m_buttonDown(button != (unsigned short)-1)
     102    , m_syntheticClickType(button == -2 ? 0 : syntheticClickType)
     103    , m_buttonDown(button != -2)
    104104    , m_relatedTarget(relatedTarget)
    105105{
     
    109109MouseEvent::MouseEvent(const AtomicString& eventType, const MouseEventInit& initializer)
    110110    : MouseRelatedEvent(eventType, initializer)
    111     , m_button(initializer.button == (unsigned short)-1 ? 0 : initializer.button)
     111    , m_button(initializer.button == -2 ? 0 : initializer.button)
    112112    , m_buttons(initializer.buttons)
    113     , m_buttonDown(initializer.button != (unsigned short)-1)
     113    , m_buttonDown(initializer.button != -2)
    114114    , m_relatedTarget(initializer.relatedTarget)
    115115{
     
    120120
    121121void MouseEvent::initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<WindowProxy>&& view, int detail,
    122     int screenX, int screenY, int clientX, int clientY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, EventTarget* relatedTarget)
     122    int screenX, int screenY, int clientX, int clientY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, short button, EventTarget* relatedTarget)
    123123{
    124124    if (isBeingDispatched())
     
    129129    m_screenLocation = IntPoint(screenX, screenY);
    130130    setModifierKeys(ctrlKey, altKey, shiftKey, metaKey);
    131     m_button = button == (unsigned short)-1 ? 0 : button;
     131    m_button = button == -2 ? 0 : button;
    132132    m_syntheticClickType = 0;
    133     m_buttonDown = button != (unsigned short)-1;
     133    m_buttonDown = button != -2;
    134134    m_relatedTarget = relatedTarget;
    135135
     
    142142// FIXME: We need this quirk because iAd Producer is calling this function with a relatedTarget that is not an EventTarget (rdar://problem/30640101).
    143143// We should remove this quirk when possible.
    144 void MouseEvent::initMouseEventQuirk(ExecState& state, ScriptExecutionContext& scriptExecutionContext, const AtomicString& type, bool canBubble, bool cancelable, RefPtr<WindowProxy>&& view, int detail, int screenX, int screenY, int clientX, int clientY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button, JSValue relatedTargetValue)
     144void MouseEvent::initMouseEventQuirk(ExecState& state, ScriptExecutionContext& scriptExecutionContext, const AtomicString& type, bool canBubble, bool cancelable, RefPtr<WindowProxy>&& view, int detail, int screenX, int screenY, int clientX, int clientY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, short button, JSValue relatedTargetValue)
    145145{
    146146    EventTarget* relatedTarget = nullptr;
  • trunk/Source/WebCore/dom/MouseEvent.h

    r245867 r246103  
    4141public:
    4242    WEBCORE_EXPORT static Ref<MouseEvent> create(const AtomicString& type, CanBubble, IsCancelable, IsComposed, MonotonicTime timestamp, RefPtr<WindowProxy>&&, int detail,
    43         const IntPoint& screenLocation, const IntPoint& windowLocation, const IntPoint& movementDelta, OptionSet<Modifier>, unsigned short button, unsigned short buttons,
     43        const IntPoint& screenLocation, const IntPoint& windowLocation, const IntPoint& movementDelta, OptionSet<Modifier>, short button, unsigned short buttons,
    4444        EventTarget* relatedTarget, double force, unsigned short syntheticClickType, DataTransfer* = nullptr, IsSimulated = IsSimulated::No, IsTrusted = IsTrusted::Yes);
    4545
     
    4747
    4848    static Ref<MouseEvent> create(const AtomicString& eventType, CanBubble, IsCancelable, IsComposed, RefPtr<WindowProxy>&&, int detail,
    49         int screenX, int screenY, int clientX, int clientY, OptionSet<Modifier>, unsigned short button, unsigned short buttons,
     49        int screenX, int screenY, int clientX, int clientY, OptionSet<Modifier>, short button, unsigned short buttons,
    5050        unsigned short syntheticClickType, EventTarget* relatedTarget);
    5151
     
    6262    WEBCORE_EXPORT void initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<WindowProxy>&&,
    6363        int detail, int screenX, int screenY, int clientX, int clientY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
    64         unsigned short button, EventTarget* relatedTarget);
     64        short button, EventTarget* relatedTarget);
    6565
    6666    void initMouseEventQuirk(JSC::ExecState&, ScriptExecutionContext&, const AtomicString& type, bool canBubble, bool cancelable, RefPtr<WindowProxy>&&,
    6767        int detail, int screenX, int screenY, int clientX, int clientY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
    68         unsigned short button, JSC::JSValue relatedTarget);
     68        short button, JSC::JSValue relatedTarget);
    6969
    70     unsigned short button() const { return m_button; }
     70    short button() const { return m_button; }
    7171    unsigned short buttons() const { return m_buttons; }
    7272    unsigned short syntheticClickType() const { return m_syntheticClickType; }
     
    8787protected:
    8888    MouseEvent(const AtomicString& type, CanBubble, IsCancelable, IsComposed, MonotonicTime timestamp, RefPtr<WindowProxy>&&, int detail,
    89         const IntPoint& screenLocation, const IntPoint& windowLocation, const IntPoint& movementDelta, OptionSet<Modifier>, unsigned short button, unsigned short buttons,
     89        const IntPoint& screenLocation, const IntPoint& windowLocation, const IntPoint& movementDelta, OptionSet<Modifier>, short button, unsigned short buttons,
    9090        EventTarget* relatedTarget, double force, unsigned short syntheticClickType, DataTransfer*, IsSimulated, IsTrusted);
    9191
    9292    MouseEvent(const AtomicString& type, CanBubble, IsCancelable, IsComposed, RefPtr<WindowProxy>&&, int detail,
    93         const IntPoint& screenLocation, const IntPoint& clientLocation, OptionSet<Modifier>, unsigned short button, unsigned short buttons,
     93        const IntPoint& screenLocation, const IntPoint& clientLocation, OptionSet<Modifier>, short button, unsigned short buttons,
    9494        unsigned short syntheticClickType, EventTarget* relatedTarget);
    9595
     
    106106    void setRelatedTarget(EventTarget& relatedTarget) final { m_relatedTarget = &relatedTarget; }
    107107
    108     unsigned short m_button { 0 };
     108    short m_button { 0 };
    109109    unsigned short m_buttons { 0 };
    110110    unsigned short m_syntheticClickType { 0 };
  • trunk/Source/WebCore/dom/MouseEvent.idl

    r237717 r246103  
    3333    readonly attribute boolean altKey;
    3434    readonly attribute boolean metaKey;
    35     readonly attribute unsigned short button;
     35    readonly attribute short button;
    3636    readonly attribute unsigned short buttons;
    3737    readonly attribute EventTarget? relatedTarget;
     
    5050        optional long screenX = 0, optional long screenY = 0, optional long clientX = 0, optional long clientY = 0,
    5151        optional boolean ctrlKey = false, optional boolean altKey = false, optional boolean shiftKey = false, optional boolean metaKey = false,
    52         optional unsigned short button = 0, optional any relatedTarget = null);
     52        optional short button = 0, optional any relatedTarget = null);
    5353
    5454    readonly attribute long offsetX;
  • trunk/Source/WebCore/dom/MouseEventInit.h

    r223264 r246103  
    3333    int clientX { 0 };
    3434    int clientY { 0 };
    35     unsigned short button { 0 };
     35    short button { 0 };
    3636    unsigned short buttons { 0 };
    3737    RefPtr<EventTarget> relatedTarget;
  • trunk/Source/WebCore/dom/MouseEventInit.idl

    r223264 r246103  
    2929    long clientX = 0;
    3030    long clientY = 0;
    31     unsigned short button = 0;
     31    short button = 0;
    3232    unsigned short buttons = 0;
    3333
  • trunk/Source/WebCore/dom/PointerEvent.cpp

    r245020 r246103  
    7272}
    7373
    74 RefPtr<PointerEvent> PointerEvent::create(const MouseEvent& mouseEvent)
     74RefPtr<PointerEvent> PointerEvent::create(short button, const MouseEvent& mouseEvent)
    7575{
    7676    auto type = pointerEventType(mouseEvent.type());
     
    7878        return nullptr;
    7979
     80    return create(type, button, mouseEvent);
     81}
     82
     83Ref<PointerEvent> PointerEvent::create(const String& type, short button, const MouseEvent& mouseEvent)
     84{
    8085    auto isEnterOrLeave = type == eventNames().pointerenterEvent || type == eventNames().pointerleaveEvent;
    8186    auto canBubble = isEnterOrLeave ? CanBubble::No : CanBubble::Yes;
    8287    auto isCancelable = isEnterOrLeave ? IsCancelable::No : IsCancelable::Yes;
    8388    auto isComposed = isEnterOrLeave ? IsComposed::No : IsComposed::Yes;
    84     return adoptRef(*new PointerEvent(type, canBubble, isCancelable, isComposed, mouseEvent));
     89    return adoptRef(*new PointerEvent(type, canBubble, isCancelable, isComposed, button, mouseEvent));
    8590}
    8691
     
    107112}
    108113
    109 PointerEvent::PointerEvent(const AtomicString& type, CanBubble canBubble, IsCancelable isCancelable, IsComposed isComposed, const MouseEvent& mouseEvent)
    110     : MouseEvent(type, canBubble, isCancelable, isComposed, mouseEvent.view(), mouseEvent.detail(), mouseEvent.screenLocation(), { mouseEvent.clientX(), mouseEvent.clientY() }, mouseEvent.modifierKeys(), mouseEvent.button(), mouseEvent.buttons(), mouseEvent.syntheticClickType(), mouseEvent.relatedTarget())
     114PointerEvent::PointerEvent(const AtomicString& type, CanBubble canBubble, IsCancelable isCancelable, IsComposed isComposed, short button, const MouseEvent& mouseEvent)
     115    : MouseEvent(type, canBubble, isCancelable, isComposed, mouseEvent.view(), mouseEvent.detail(), mouseEvent.screenLocation(), { mouseEvent.clientX(), mouseEvent.clientY() }, mouseEvent.modifierKeys(), button, mouseEvent.buttons(), mouseEvent.syntheticClickType(), mouseEvent.relatedTarget())
    111116    , m_isPrimary(true)
    112117{
  • trunk/Source/WebCore/dom/PointerEvent.h

    r245867 r246103  
    7676    }
    7777
    78     static RefPtr<PointerEvent> create(const MouseEvent&);
     78    static RefPtr<PointerEvent> create(short button, const MouseEvent&);
     79    static Ref<PointerEvent> create(const String& type, short button, const MouseEvent&);
    7980    static Ref<PointerEvent> create(const String& type, PointerID, const String& pointerType, IsPrimary = IsPrimary::No);
    8081
     
    116117    PointerEvent();
    117118    PointerEvent(const AtomicString&, Init&&);
    118     PointerEvent(const AtomicString& type, CanBubble, IsCancelable, IsComposed, const MouseEvent&);
     119    PointerEvent(const AtomicString& type, CanBubble, IsCancelable, IsComposed, short button, const MouseEvent&);
    119120    PointerEvent(const AtomicString& type, CanBubble, IsCancelable, IsComposed, PointerID, const String& pointerType, IsPrimary);
    120121#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
  • trunk/Source/WebCore/loader/NavigationAction.h

    r245796 r246103  
    9595        LayoutPoint absoluteLocation;
    9696        FloatPoint locationInRootViewCoordinates;
    97         unsigned short button;
     97        short button;
    9898        unsigned short syntheticClickType;
    9999        bool buttonDown;
  • trunk/Source/WebCore/page/PointerCaptureController.cpp

    r246074 r246103  
    232232#endif
    233233
     234RefPtr<PointerEvent> PointerCaptureController::pointerEventForMouseEvent(const MouseEvent& mouseEvent)
     235{
     236    const auto& type = mouseEvent.type();
     237    const auto& names = eventNames();
     238
     239    auto iterator = m_activePointerIdsToCapturingData.find(mousePointerID);
     240    ASSERT(iterator != m_activePointerIdsToCapturingData.end());
     241    auto& capturingData = iterator->value;
     242
     243    short newButton = mouseEvent.button();
     244    short button = newButton == capturingData.previousMouseButton ? -1 : newButton;
     245
     246    // https://w3c.github.io/pointerevents/#chorded-button-interactions
     247    // Some pointer devices, such as mouse or pen, support multiple buttons. In the Mouse Event model, each button
     248    // press produces a mousedown and mouseup event. To better abstract this hardware difference and simplify
     249    // cross-device input authoring, Pointer Events do not fire overlapping pointerdown and pointerup events
     250    // for chorded button presses (depressing an additional button while another button on the pointer device is
     251    // already depressed).
     252    if (type == names.mousedownEvent || type == names.mouseupEvent) {
     253        // We're already active and getting another mousedown, this means that we should dispatch
     254        // a pointermove event and let the button state show the newly depressed button.
     255        if (type == names.mousedownEvent && capturingData.pointerIsPressed)
     256            return PointerEvent::create(names.pointermoveEvent, button, mouseEvent);
     257
     258        // We're active and the mouseup still has some pressed button, this means we should dispatch
     259        // a pointermove event.
     260        if (type == names.mouseupEvent && capturingData.pointerIsPressed && mouseEvent.buttons() > 0)
     261            return PointerEvent::create(names.pointermoveEvent, button, mouseEvent);
     262    }
     263
     264    capturingData.previousMouseButton = newButton;
     265
     266    return PointerEvent::create(button, mouseEvent);
     267}
     268
    234269void PointerCaptureController::dispatchEvent(PointerEvent& event, EventTarget* target)
    235270{
  • trunk/Source/WebCore/page/PointerCaptureController.h

    r245809 r246103  
    5050    void elementWasRemoved(Element&);
    5151
     52    RefPtr<PointerEvent> pointerEventForMouseEvent(const MouseEvent&);
     53
    5254#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
    5355    void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&);
     
    6971        bool preventsCompatibilityMouseEvents { false };
    7072        bool pointerIsPressed { false };
     73        short previousMouseButton { -1 };
    7174    };
    7275
  • trunk/Source/WebCore/platform/PlatformMouseEvent.h

    r245639 r246103  
    4343
    4444    // These button numbers match the ones used in the DOM API, 0 through 2, except for NoButton which isn't specified.
    45     enum MouseButton : int8_t { NoButton = -1, LeftButton, MiddleButton, RightButton };
     45    // We use -2 for NoButton because -1 is a valid value in the DOM API for Pointer Events for pointermove events that
     46    // indicate that the pressed mouse button hasn't changed since the last event.
     47    enum MouseButton : int8_t { LeftButton = 0, MiddleButton, RightButton, NoButton = -2 };
    4648    enum SyntheticClickType : int8_t { NoTap, OneFingerTap, TwoFingerTap };
    4749
     
    137139#if COMPILER(MSVC)
    138140    // These functions are necessary to work around the fact that MSVC will not find a most-specific
    139     // operator== to use after implicitly converting MouseButton to an unsigned short.
    140     inline bool operator==(unsigned short a, MouseButton b)
     141    // operator== to use after implicitly converting MouseButton to a short.
     142    inline bool operator==(short a, MouseButton b)
    141143    {
    142         return a == static_cast<unsigned short>(b);
     144        return a == static_cast<short>(b);
    143145    }
    144146
    145     inline bool operator!=(unsigned short a, MouseButton b)
     147    inline bool operator!=(short a, MouseButton b)
    146148    {
    147         return a != static_cast<unsigned short>(b);
     149        return a != static_cast<short>(b);
    148150    }
    149151#endif
  • trunk/Source/WebKit/ChangeLog

    r246102 r246103  
     12019-06-01  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] Add support for chorded button interactions
     4        https://bugs.webkit.org/show_bug.cgi?id=198462
     5
     6        Reviewed by Dean Jackson.
     7
     8        Update to use -2 instead of -1 for NoButton.
     9
     10        * Shared/API/c/WKEvent.h:
     11        * Shared/WebEvent.h:
     12
    1132019-06-05  Michael Catanzaro  <mcatanzaro@igalia.com>
    214
  • trunk/Source/WebKit/Shared/API/c/WKEvent.h

    r206828 r246103  
    4343
    4444enum {
    45     kWKEventMouseButtonNoButton = -1,
    4645    kWKEventMouseButtonLeftButton = 0,
    4746    kWKEventMouseButtonMiddleButton = 1,
    4847    kWKEventMouseButtonRightButton = 2,
     48    kWKEventMouseButtonNoButton = -2
    4949};
    5050typedef int32_t WKEventMouseButton;
  • trunk/Source/WebKit/Shared/WebEvent.h

    r244975 r246103  
    128128public:
    129129    enum Button {
    130         NoButton = -1,
    131         LeftButton,
     130        LeftButton = 0,
    132131        MiddleButton,
    133         RightButton
     132        RightButton,
     133        NoButton = -2
    134134    };
    135135
  • trunk/Source/WebKitLegacy/mac/ChangeLog

    r246045 r246103  
     12019-06-01  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] Add support for chorded button interactions
     4        https://bugs.webkit.org/show_bug.cgi?id=198462
     5
     6        Reviewed by Dean Jackson.
     7
     8        Update -[DOMMouseEvent button] to be a "short" and update the noButton value from -1 to -2.
     9
     10        * DOM/DOMMouseEvent.h:
     11        * DOM/DOMMouseEvent.mm:
     12        (-[DOMMouseEvent button]):
     13        * WebView/WebPDFView.mm:
     14        (-[WebPDFView PDFViewWillClickOnLink:withURL:]):
     15
    1162019-06-03  Rob Buis  <rbuis@igalia.com>
    217
  • trunk/Source/WebKitLegacy/mac/DOM/DOMMouseEvent.h

    r231383 r246103  
    4141@property (readonly) BOOL altKey;
    4242@property (readonly) BOOL metaKey;
    43 @property (readonly) unsigned short button;
     43@property (readonly) short button;
    4444@property (readonly, strong) id <DOMEventTarget> relatedTarget;
    4545@property (readonly) int offsetX WEBKIT_AVAILABLE_MAC(10_5);
  • trunk/Source/WebKitLegacy/mac/DOM/DOMMouseEvent.mm

    r238771 r246103  
    9393}
    9494
    95 - (unsigned short)button
     95- (short)button
    9696{
    9797    WebCore::JSMainThreadNullState state;
  • trunk/Source/WebKitLegacy/mac/WebView/WebPDFView.mm

    r244405 r246103  
    961961    NSWindow *window = [sender window];
    962962    NSEvent *nsEvent = [window currentEvent];
    963     const int noButton = -1;
     963    const int noButton = -2;
    964964    int button = noButton;
    965965    RefPtr<Event> event;
  • trunk/Tools/ChangeLog

    r246097 r246103  
     12019-06-01  Antoine Quint  <graouts@apple.com>
     2
     3        [Pointer Events] Add support for chorded button interactions
     4        https://bugs.webkit.org/show_bug.cgi?id=198462
     5
     6        Reviewed by Dean Jackson.
     7
     8        Until now, MouseEvent.buttons would always return 0 when used within DRT and WKTR as [NSEvent pressedMouseButtons], used
     9        by PlatformMouseEventBuilder to set the m_buttons value eventually used to set MouseEvent.buttons, not account for the
     10        NSEvent created through the eventSender JS object in tests. To fix this, we now track the pressed mouse buttons within
     11        DRT and WKTR as mouseDown() and mouseUp() are called, and swizzle [NSEvent pressedMouseButtons] to return that value.
     12
     13        In the case of DRT, one test would fail when swizzling this method in the case where the target view for the event would
     14        be the DRTMockScroller, a subclass of NSScroller. So we only swizzle when the target view is *not* an NSScroller or a
     15        subclass.
     16
     17        Finally, we change the NoMouseButton enum value from -1 to -2 to adjust to MouseEvent.button now being a "short".
     18
     19        * DumpRenderTree/mac/EventSendingController.mm:
     20        (swizzledEventPressedMouseButtons):
     21        (-[EventSendingController mouseDown:withModifiers:]):
     22        (-[EventSendingController mouseUp:withModifiers:]):
     23        (-[EventSendingController mouseMoveToX:Y:]):
     24        * TestWebKitAPI/Tests/mac/IsNavigationActionTrusted.mm:
     25        * WebKitTestRunner/EventSenderProxy.h:
     26        (WTR::EventSenderProxy::mouseButtonsCurrentlyDown const):
     27        * WebKitTestRunner/mac/EventSenderProxy.mm:
     28        (WTR::swizzledEventPressedMouseButtons):
     29        (WTR::EventSenderProxy::mouseDown):
     30        (WTR::EventSenderProxy::mouseUp):
     31        (WTR::EventSenderProxy::mouseMoveTo):
     32
    1332019-06-04  Chris Dumez  <cdumez@apple.com>
    234
  • trunk/Tools/DumpRenderTree/mac/EventSendingController.mm

    r239275 r246103  
    3333#import "EventSendingController.h"
    3434
     35#import "ClassMethodSwizzler.h"
    3536#import "DumpRenderTree.h"
    3637#import "DumpRenderTreeDraggingInfo.h"
     
    7879    MiddleMouseButton = 1,
    7980    RightMouseButton = 2,
    80     NoMouseButton = -1
     81    NoMouseButton = -2
    8182};
    8283
     
    9495NSMutableArray *savedMouseEvents; // mouse events sent between mouseDown and mouseUp are stored here, and then executed at once.
    9596BOOL replayingSavedEvents;
    96 
     97unsigned mouseButtonsCurrentlyDown = 0;
    9798
    9899#if PLATFORM(IOS_FAMILY)
     
    562563}
    563564
     565#if !PLATFORM(IOS_FAMILY)
     566static NSUInteger swizzledEventPressedMouseButtons()
     567{
     568    return mouseButtonsCurrentlyDown;
     569}
     570#endif
     571
    564572- (void)mouseDown:(int)buttonNumber withModifiers:(WebScriptObject*)modifiers
    565573{
     574    mouseButtonsCurrentlyDown |= (1 << buttonNumber);
     575
    566576    [[[mainFrame frameView] documentView] layout];
    567577    [self updateClickCountForButton:buttonNumber];
     
    589599        [NSApp _setCurrentEvent:event];
    590600#endif
    591         [subView mouseDown:event];
     601        {
     602#if !PLATFORM(IOS_FAMILY)
     603            auto eventPressedMouseButtonsSwizzler = ![subView isKindOfClass:[NSScroller class]] ? std::make_unique<ClassMethodSwizzler>([NSEvent class], @selector(pressedMouseButtons), reinterpret_cast<IMP>(swizzledEventPressedMouseButtons)) : NULL;
     604#endif
     605            [subView mouseDown:event];
     606        }
    592607#if !PLATFORM(IOS_FAMILY)
    593608        [NSApp _setCurrentEvent:nil];
     
    638653- (void)mouseUp:(int)buttonNumber withModifiers:(WebScriptObject*)modifiers
    639654{
     655    mouseButtonsCurrentlyDown &= ~(1 << buttonNumber);
     656
    640657    if (dragMode && !replayingSavedEvents) {
    641658        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[EventSendingController instanceMethodSignatureForSelector:@selector(mouseUp:withModifiers:)]];
     
    678695    [NSApp _setCurrentEvent:event];
    679696#endif
    680     [targetView mouseUp:event];
     697    {
     698#if !PLATFORM(IOS_FAMILY)
     699        auto eventPressedMouseButtonsSwizzler = ![targetView isKindOfClass:[NSScroller class]] ? std::make_unique<ClassMethodSwizzler>([NSEvent class], @selector(pressedMouseButtons), reinterpret_cast<IMP>(swizzledEventPressedMouseButtons)) : NULL;
     700#endif
     701        [targetView mouseUp:event];
     702    }
    681703#if !PLATFORM(IOS_FAMILY)
    682704    [NSApp _setCurrentEvent:nil];
     
    763785                    [[draggingInfo draggingSource] draggedImage:[draggingInfo draggedImage] movedTo:lastMousePosition];
    764786                [[mainFrame webView] draggingUpdated:draggingInfo];
    765             } else
     787            } else {
     788#if !PLATFORM(IOS_FAMILY)
     789                auto eventPressedMouseButtonsSwizzler = ![subView isKindOfClass:[NSScroller class]] ? std::make_unique<ClassMethodSwizzler>([NSEvent class], @selector(pressedMouseButtons), reinterpret_cast<IMP>(swizzledEventPressedMouseButtons)) : NULL;
     790#endif
    766791                [subView mouseDragged:event];
    767 #endif
    768         } else
     792            }
     793#endif
     794        } else {
     795#if !PLATFORM(IOS_FAMILY)
     796            auto eventPressedMouseButtonsSwizzler = ![subView isKindOfClass:[NSScroller class]] ? std::make_unique<ClassMethodSwizzler>([NSEvent class], @selector(pressedMouseButtons), reinterpret_cast<IMP>(swizzledEventPressedMouseButtons)) : NULL;
     797#endif
    769798            [subView mouseMoved:event];
     799        }
    770800#if !PLATFORM(IOS_FAMILY)
    771801        [NSApp _setCurrentEvent:nil];
  • trunk/Tools/TestWebKitAPI/Tests/mac/IsNavigationActionTrusted.mm

    r242339 r246103  
    3434const static NSURL *targetUrl = [[NSURL alloc] initWithString:@"http://www.example.com/"];
    3535const static unsigned expectedModifierFlags = 0;
    36 const static int expectedButtonNumber = -1;
     36const static int expectedButtonNumber = -2;
    3737
    3838const static int expectedWKButtonNumber = 0; // unlike DOM spec, 0 is the value for no button in Cocoa.
  • trunk/Tools/WebKitTestRunner/EventSenderProxy.h

    r243689 r246103  
    7777    void keyDown(WKStringRef key, WKEventModifiers, unsigned location);
    7878
     79#if PLATFORM(COCOA)
     80    unsigned mouseButtonsCurrentlyDown() const { return m_mouseButtonsCurrentlyDown; }
     81#endif
     82
    7983#if ENABLE(TOUCH_EVENTS)
    8084    // Touch events.
     
    138142#if PLATFORM(COCOA)
    139143    int eventNumber;
     144    unsigned m_mouseButtonsCurrentlyDown { 0 };
    140145#elif PLATFORM(GTK)
    141146    Deque<WTREventQueueItem> m_eventQueue;
  • trunk/Tools/WebKitTestRunner/mac/EventSenderProxy.mm

    r244820 r246103  
    205205    MiddleMouseButton = 1,
    206206    RightMouseButton = 2,
    207     NoMouseButton = -1
     207    NoMouseButton = -2
    208208};
    209209
     
    302302}
    303303
     304static NSUInteger swizzledEventPressedMouseButtons()
     305{
     306    return TestController::singleton().eventSenderProxy()->mouseButtonsCurrentlyDown();
     307}
     308
    304309void EventSenderProxy::mouseDown(unsigned buttonNumber, WKEventModifiers modifiers)
    305310{
     311    m_mouseButtonsCurrentlyDown |= (1 << buttonNumber);
     312
    306313    updateClickCountForButton(buttonNumber);
    307314
     
    319326    NSView *targetView = [m_testController->mainWebView()->platformView() hitTest:[event locationInWindow]];
    320327    if (targetView) {
     328        auto eventPressedMouseButtonsSwizzler = std::make_unique<ClassMethodSwizzler>([NSEvent class], @selector(pressedMouseButtons), reinterpret_cast<IMP>(swizzledEventPressedMouseButtons));
    321329        [NSApp _setCurrentEvent:event];
    322330        [targetView mouseDown:event];
     
    329337void EventSenderProxy::mouseUp(unsigned buttonNumber, WKEventModifiers modifiers)
    330338{
     339    m_mouseButtonsCurrentlyDown &= ~(1 << buttonNumber);
     340
    331341    NSEventType eventType = eventTypeForMouseButtonAndAction(buttonNumber, MouseUp);
    332342    NSEvent *event = [NSEvent mouseEventWithType:eventType
     
    348358
    349359    ASSERT(targetView);
     360    auto eventPressedMouseButtonsSwizzler = std::make_unique<ClassMethodSwizzler>([NSEvent class], @selector(pressedMouseButtons), reinterpret_cast<IMP>(swizzledEventPressedMouseButtons));
    350361    [NSApp _setCurrentEvent:event];
    351362    [targetView mouseUp:event];
     
    583594    NSView *targetView = isDrag ? m_testController->mainWebView()->platformView() : [m_testController->mainWebView()->platformView() hitTest:windowLocation];
    584595    if (targetView) {
     596        auto eventPressedMouseButtonsSwizzler = std::make_unique<ClassMethodSwizzler>([NSEvent class], @selector(pressedMouseButtons), reinterpret_cast<IMP>(swizzledEventPressedMouseButtons));
    585597        [NSApp _setCurrentEvent:event];
    586598        if (isDrag)
Note: See TracChangeset for help on using the changeset viewer.