Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 17c30e3cfa7cb856ba46e621918774758aab0da3
https://github.com/WebKit/WebKit/commit/17c30e3cfa7cb856ba46e621918774758aab0da3
Author: Richard Robinson <[email protected]>
Date: 2026-06-25 (Thu, 25 Jun 2026)
Changed paths:
M Source/WebCore/page/EventHandler.cpp
M Source/WebCore/page/EventHandler.h
M Source/WebCore/page/mac/EventHandlerMac.mm
M Source/WebKit/UIProcess/mac/WKTextSelectionController.h
M Source/WebKit/UIProcess/mac/WKTextSelectionController.swift
M Source/WebKit/UIProcess/mac/WebViewImpl.mm
M Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm
M Source/WebKit/WebProcess/WebPage/WebPage.h
M Tools/TestWebKitAPI/Tests/WebKit/WebPage/AppKitGesturesTests.swift
Log Message:
-----------
[AppKit Gestures] Clicking and dragging text selection to the edge of the
window does not autoscroll
https://bugs.webkit.org/show_bug.cgi?id=317717
rdar://176424187
Reviewed by Abrar Rahman Protyasha.
On macOS, when using the AppKit-gestures text interaction path (driven by
NSTextSelectionManager), click-dragging a selection to the edge of the window
did not autoscroll the page. The selection stopped growing at whatever was
already on screen, so it was impossible to select past the visible content
without manually scrolling first. iOS already supports this via UIKit's
UITextAutoscrolling protocol, which performs edge detection and drives the
web process's autoscroll timer; AppKit has no equivalent, so nothing started
or sustained the scroll.
Implement selection-drag autoscroll for macOS by reusing the existing
selection-autoscroll machinery that iOS relies on (EventHandler's
m_isAutoscrolling / m_targetAutoscrollPositionInRootView, AutoscrollController's
50ms Selection timer, and the WebPage StartAutoscrollAtPosition /
CancelAutoscroll messages). The decision of when to autoscroll lives entirely
in the web process, which already computes the visible content rect and owns
the edge-band constants, so the UI process does not duplicate that geometry.
How it works:
- On each extent-point update during a range-selection drag (the messages
the UI process already sends as the cursor moves, and re-sends as the page
scrolls), WebPage::updateSelectionWithExtentPointAndBoundary asks the
EventHandler whether the point sits within the visible-edge band. If so it
starts (or keeps) selection autoscroll targeting that point; otherwise it
cancels. This is re-evaluated every update, so holding the cursor near the
edge keeps scrolling and dragging back toward the middle stops it -- the
macOS counterpart to UIKit's UITextAutoscrolling edge detection.
- While autoscrolling,
EventHandler::targetPositionInWindowForSelectionAutoscroll
pushes the target point past the nearest visible-content edge, scaling the
push by how deep into the edge band the point is. Because the push is a
fixed
distance past the edge in root-view coordinates, the autoscroll timer's
windowToContents mapping yields a stable per-tick scroll delta, so the page
keeps scrolling at a constant velocity for as long as the gesture holds near
(or past) the edge -- without the UI process having to re-push a target.
- As the page scrolls, WebViewImpl::pageDidScroll asks the text selection
controller to re-extend the selection toward the last drag point, so the
selection keeps growing into the newly revealed content. This mirrors the
iOS -updateSelection re-extension.
The edge-detection predicate (isPointNearSelectionAutoscrollEdge) and the
target-push (pushSelectionAutoscrollTargetPastVisibleEdges) share a single
helper, selectionAutoscrollGeometry, for the visible rect and page-scale
factor. Sharing one source of truth guarantees the "should we scroll" decision
and "how far past the edge" computation use the same edge band, so they cannot
disagree (e.g. when the page is magnified to a scale below 1).
While autoscrolling on Cocoa, EventHandler::updateSelectionForMouseDrag is
suppressed: the selection is re-extended by the UI process toward the live drag
point as the page scrolls, so re-extending here from the stale last-known mouse
position would fight that. This is a no-op on iOS, where
supportsSelectionUpdatesOnMouseDrag() already returns false; the corresponding
preprocessor guard is widened from !PLATFORM(IOS_FAMILY) to !PLATFORM(COCOA) to
match.
* Source/WebCore/page/EventHandler.cpp:
(WebCore::EventHandler::updateSelectionForMouseDrag): Bail during autoscroll on
Cocoa so the UI-process-driven re-extension is authoritative.
* Source/WebCore/page/EventHandler.h:
* Source/WebCore/page/mac/EventHandlerMac.mm:
(WebCore::selectionAutoscrollGeometry): Added; shared visible-rect + zoom scale.
(WebCore::EventHandler::isPointNearSelectionAutoscrollEdge): Added.
(WebCore::EventHandler::targetPositionInWindowForSelectionAutoscroll): Push the
target past the nearest visible edge while autoscrolling.
* Source/WebKit/WebProcess/WebPage/WebPage.h:
* Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm:
(WebKit::WebPage::rendererForSelectionAutoscroll): Added; factored out renderer
resolution shared by the start path and the extent-point edge check.
(WebKit::WebPage::startAutoscrollAtPosition): Use the shared helper.
(WebKit::WebPage::updateSelectionWithExtentPointAndBoundary): On macOS, start or
cancel selection autoscroll based on edge proximity.
* Source/WebKit/UIProcess/mac/WKTextSelectionController.h:
* Source/WebKit/UIProcess/mac/WKTextSelectionController.swift:
(reextendSelectionForAutoscrollIfNeeded): Re-extend toward the last drag point
on scroll; gated on an in-flight drag rather than UI-cached autoscroll state.
(beginRangeSelection / continueRangeSelection / endRangeSelection): Track the
last extent point; cancel autoscroll at gesture begin/end as a safety net.
* Source/WebKit/UIProcess/mac/WebViewImpl.mm:
(WebKit::WebViewImpl::pageDidScroll): Re-extend the selection as the page
autoscrolls.
* Tools/TestWebKitAPI/Tests/WebKit/WebPage/AppKitGesturesTests.swift:
(draggingSelectionToWindowEdgeAutoscrolls): Added.
(holdingSelectionDragNearEdgeKeepsScrolling): Added; verifies the scroll
continues across the hold rather than bursting and stopping early.
(holdingSelectionDragMidContentDoesNotAutoscroll): Added.
(selectionAutoscrollStopsAfterGestureEnds): Added.
(draggingSelectionToTopEdgeScrollsUp): Added.
Canonical link: https://commits.webkit.org/315834@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications