Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 80eaeca1f565e58a3df57b5d6b2a77cb40446dea
https://github.com/WebKit/WebKit/commit/80eaeca1f565e58a3df57b5d6b2a77cb40446dea
Author: Simon Fraser <[email protected]>
Date: 2026-04-28 (Tue, 28 Apr 2026)
Changed paths:
M Source/WebCore/PAL/pal/spi/cocoa/QuartzCoreSPI.h
M Source/WebKit/Configurations/AllowedSPI.toml
M
Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeEventDispatcher.h
M
Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeEventDispatcher.mm
M Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm
Log Message:
-----------
Occasional flicker of bad layer offsets when positions are adjusted by scroll
anchoring (or other programmatic scrolling)
https://bugs.webkit.org/show_bug.cgi?id=313486
rdar://175706332
Reviewed by Abrar Rahman Protyasha.
On macOS, we process wheel events in the scrolling thread, which can happen
concurrently
with the main thread receiving a
RemoteLayerTreeTransaction/RemoteScrollingCoordinatorTransaction.
If the web process issued a programmatic scroll (e.g. for a scroll anchoring
adjustment),
the layer tree transaction may contain new layer backing stores with the newly
rendered
scroll offset, and the scrolling transaction will have nodes with
RequestedScrollPositions.
To avoid flashes of incorrect content, it's essential that the new positions
and backing
stores show up in the same Core Animation commit.
However there was no guarantee of that. When the main thread receives the
transaction
with RequestedScrollPositions, the scrolling thread may have recently processed
wheel
events, and have pending layer position updates. The main thread may then
process the
RequestedScrollPositions, which modify ScrollingTreeNode
`currentScrollPosition`, which
affects layer positions. Now, if the scrolling thread's CACommit happens before
the
main thread, the scrolling thread commits positions affected by programmatic
scrolls,
but the layer backing stores still show the old state; this is the flash of bad
state.
Reduce the window of opportunity here by changing the scrolling thread to use
explict
CATransaction flushing, rather than relying on automatic runloop observer-based
commits,
which was the main cause of raceyness. We can't just use explict
`begin`/`commit` pairs
because there are code paths that touch scrollbar layers that open implicit
transactions;
those still need to get flushed.
We call `[CATransaction flush]` for any `ScrollingThread::dispatch()` that can
touch layers; the most common is the case that updates layers and animations,
and has to flush before updating animations (which uses
CAPresentationModifierGroup).
Now that we have explicit flushing, we can, if necessary, use it to eliminate
the
race in future.
* Source/WebCore/PAL/pal/spi/cocoa/QuartzCoreSPI.h:
* Source/WebKit/Configurations/AllowedSPI.toml: Just whitespace.
* Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeEventDispatcher.h:
* Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeEventDispatcher.mm:
(WebKit::RemoteLayerTreeEventDispatcher::scrollingThreadHandleWheelEvent):
(WebKit::RemoteLayerTreeEventDispatcher::wheelEventHandlingCompleted):
(WebKit::RemoteLayerTreeEventDispatcher::didRefreshDisplay):
tryToApplyLayerPositions() doesn't
have to run with the lock held.
(WebKit::RemoteLayerTreeEventDispatcher::updateLayerPositionsAndAnimations):
(WebKit::RemoteLayerTreeEventDispatcher::delayedRenderingUpdateDetectionTimerFired):
(WebKit::RemoteLayerTreeEventDispatcher::waitForRenderingUpdateCompletionOrTimeout):
(WebKit::RemoteLayerTreeEventDispatcher::timeline):
* Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm:
(WebKit::RemoteScrollingTreeMac::RemoteScrollingTreeMac):
Canonical link: https://commits.webkit.org/312233@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications