Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 26475c7bd8ca76d414f8723243d61a7637907301
https://github.com/WebKit/WebKit/commit/26475c7bd8ca76d414f8723243d61a7637907301
Author: Abrar Rahman Protyasha <[email protected]>
Date: 2026-05-19 (Tue, 19 May 2026)
Changed paths:
M Source/WebKit/UIProcess/mac/PageClientImplMac.mm
M Source/WebKit/UIProcess/mac/WKAppKitGestureController.h
M Source/WebKit/UIProcess/mac/WKAppKitGestureController.mm
M Source/WebKit/UIProcess/mac/WKTextSelectionController.swift
M Source/WebKit/UIProcess/mac/WebViewImpl.h
M Source/WebKit/UIProcess/mac/WebViewImpl.mm
M Tools/TestWebKitAPI/Helpers/cocoa/JavaScriptMessages.swift
M Tools/TestWebKitAPI/Helpers/cocoa/JavaScriptTypes.swift
M Tools/TestWebKitAPI/Tests/WebKit/WebPage/AppKitGesturesTests.swift
Log Message:
-----------
[AppKit Gestures] Disambiguate drag-and-drop from text selection during
press-and-drag
https://bugs.webkit.org/show_bug.cgi?id=314870
rdar://176383341
Reviewed by Richard Robinson.
Currently, any draggable element (link, image, `draggable="true"`, etc.)
is siltently ignored in favor of text selection extensions when starting
a press-and-drag interaction. This is because NSTextSelectionManager
gestures recognize before WebKit can disambiguate this interaction.
This patch builds on top of 312982@main, which ported over async gesture
gates for AppKit gesture recognizers. We use this gesture to defer the
text selection gestures until the web process has reported the hit-test
content. On response, the deferring gesture either fails and lets the
text selection gestures proceed or transitions to .Ended, excluding the
text selection gestures and letting our drag press gesture win. We allow
our drag press gesture to win when the hit test reports draggable
content the press point.
In service of this patch, we also refactor text selection drag-and-drops.
Concretely, we let WKTextSelectionController launder the gesture it is
provided by NSTextSelectionManager via setTextSelectionDragGesture:...,
whose state is then read to perform the same mouseDown/Dragged sequences
we do elsewhere (to invoke drag-and-drop).
Non-exhaustive list of important changes, all made to solve this gesture
disambiguation problem:
- WKAppKitGestureController gains a position-information cache modeled
after the one in WKContentViewInteraction. Pending handlers are paired
with the request they were enqueued for, and only fire when the arriving
info matches.
- WebViewImpl::cancelDrag() consolidates the drag-cancel cleanup
(canceling the WebProcess drag and clearing the gesture controller's
drag state) so each early-return path in WebViewImpl::startDrag clears
both consistently.
Test: AppKitGesturesTests.pressDragOverTextCreatesSelection
AppKitGesturesTests.pressDragOnLinkInitiatesDragAndDrop
AppKitGesturesTests.pressDragOnExistingSelectionDoesNotExtendSelection
* Source/WebKit/UIProcess/mac/PageClientImplMac.mm:
(WebKit::PageClientImpl::didCommitLoadForMainFrame):
(WebKit::PageClientImpl::positionInformationDidChange):
* Source/WebKit/UIProcess/mac/WKAppKitGestureController.h:
* Source/WebKit/UIProcess/mac/WKAppKitGestureController.mm:
(representsDraggableElement):
(-[WKAppKitGestureController setUpGestureRecognizers]):
(-[WKAppKitGestureController setUpDragPressGestureRecognizer]):
(-[WKAppKitGestureController setUpDragDeferringGestureRecognizer]):
(-[WKAppKitGestureController addGesturesToWebView]):
(-[WKAppKitGestureController enableGesturesIfNeeded]):
(-[WKAppKitGestureController
deferringGestureRecognizer:shouldDeferOtherGestureRecognizer:]):
(-[WKAppKitGestureController
deferringGestureRecognizer:shouldDeferGesturesForEventThatWillBeginAction:]):
(-[WKAppKitGestureController
deferringGestureRecognizer:didEndActionWithEvent:]):
(-[WKAppKitGestureController deferringGestureRecognizer:didTransitionToState:]):
(-[WKAppKitGestureController _invalidateCurrentPositionInformation]):
(-[WKAppKitGestureController didCommitLoadForMainFrame]):
(-[WKAppKitGestureController requestAsynchronousPositionInformationUpdate:]):
(-[WKAppKitGestureController doAfterPositionInformationUpdate:forRequest:]):
(-[WKAppKitGestureController _currentPositionInformationIsValidForRequest:]):
(-[WKAppKitGestureController _hasValidOutstandingPositionInformationRequest:]):
(-[WKAppKitGestureController
_invokeAndRemovePendingHandlersValidForCurrentPositionInformation]):
(-[WKAppKitGestureController positionInformationDidChange:]):
(-[WKAppKitGestureController _dragPressShouldBeginAtLocation:]):
(-[WKAppKitGestureController activeDragGestureRecognizer]):
(-[WKAppKitGestureController setTextSelectionDragGesture:completionHandler:]):
(-[WKAppKitGestureController setGestureDraggingSession:]):
(-[WKAppKitGestureController clearGestureDragState]):
(-[WKAppKitGestureController reset]):
(-[WKAppKitGestureController
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]):
(-[WKAppKitGestureController
gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:]):
(-[WKAppKitGestureController gestureRecognizerShouldBegin:]):
(-[WKAppKitGestureController _gestureRecognizer:canPreventGestureRecognizer:]):
* Source/WebKit/UIProcess/mac/WKTextSelectionController.swift:
(WKTextSelectionController.showContextMenu(at:)):
(WKTextSelectionController.dragSelection(withGesture:completionHandler:)):
(WKTextSelectionController.textSelectionDragGestureUpdated(_:)):
* Source/WebKit/UIProcess/mac/WebViewImpl.h:
* Source/WebKit/UIProcess/mac/WebViewImpl.mm:
(WebKit::WebViewImpl::cancelDrag):
(WebKit::WebViewImpl::startDrag):
(WebKit::WebViewImpl::setTextSelectionDragGesture):
(WebKit::WebViewImpl::invalidateCachedPositionInformation):
(WebKit::WebViewImpl::positionInformationDidChange):
* Tools/TestWebKitAPI/Helpers/cocoa/JavaScriptMessages.swift:
(GetSelection.expression):
Address a minor latest issue with the selection JS helper. It is
possible for non-editable content to have _no_ selection at all (i.e.
anchorNode === null and rangeCount === 0). In these cases, we were
still unconditionally accessing selection.acnhorNode.parentElement,
which threw a JS eval exception. Instead, we want to encode this as a
`.none` case in JavaScriptSelection, which we can then incorporate in
the pressDragOnLinkInitiatesDragAndDrop test.
* Tools/TestWebKitAPI/Helpers/cocoa/JavaScriptTypes.swift:
(JavaScriptSelection.encoded):
* Tools/TestWebKitAPI/Tests/WebKit/WebPage/AppKitGesturesTests.swift:
(AppKitGesturesTests.pressDragOverTextCreatesSelection(_:)):
(AppKitGesturesTests.pressDragOnLinkInitiatesDragAndDrop):
(AppKitGesturesTests.pressDragOnExistingSelectionDoesNotExtendSelection):
Canonical link: https://commits.webkit.org/313504@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications