Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: c963a9e4decec5946b7b9587c49c042100aa2635
      
https://github.com/WebKit/WebKit/commit/c963a9e4decec5946b7b9587c49c042100aa2635
  Author: Chris Dumez <[email protected]>
  Date:   2026-09-19 (Sat, 19 Sep 2026)

  Changed paths:
    M Source/WebCore/bindings/js/ScriptController.cpp
    M Source/WebCore/page/LocalDOMWindow.h
    M Tools/TestWebKitAPI/Tests/WebKit/WKWebView/AsyncFunction.mm

  Log Message:
  -----------
  Regression(316338@main) “Copy to clipboard” button on some sites sometimes 
does not copy the first time
https://bugs.webkit.org/show_bug.cgi?id=324512
rdar://186521201

Reviewed by Ryosuke Niwa and Abrar Rahman Protyasha.

Script evaluated on behalf of the client (e.g. WKWebView's evaluateJavaScript:) 
runs as if it were
triggered by a user gesture. Since 265168@main the transient activation this 
grants is taken back
when the gesture ends by calling LocalDOMWindow::consumeTransientActivation(), 
which sets the last
activation timestamp of every window in the frame tree to -infinity. That does 
not merely undo the
forced activation, it also discards transient activation the user had genuinely 
given the page.

Safari evaluates JavaScript in the page a few milliseconds after a click, so a 
page calling an API
gated on transient activation from its click handler can find that activation 
already gone. This
went unnoticed until 316338@main made the async clipboard API require transient 
activation instead
of UserGestureIndicator::processingUserGesture(), which is neither consumable 
nor scoped to a
window: writes from a click handler now intermittently reject with 
NotAllowedError, leaving the
previous pasteboard contents in place. Nothing about this is clipboard 
specific; any API gated on
transient activation was affected.

Remember the activation each window had before the forced gesture grants its 
own, and take back only
what was granted. If a window's activation has changed since, because of a real 
user gesture or
because the script consumed it, that takes precedence. Ancestor frames in other 
processes can only
be told to consume their activation, so those keep the previous behavior for 
now.

Test: AsyncFunction.TransientActivationFromUserGestureIsPreserved

* Source/WebCore/bindings/js/ScriptController.cpp:
(WebCore::ForcedUserGestureScope::ForcedUserGestureScope):
(WebCore::ForcedUserGestureScope::previousActivations):
(WebCore::ScriptController::executeScriptInWorld):
* Source/WebCore/page/LocalDOMWindow.h:
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/AsyncFunction.mm:
(TestWebKitAPI::hasTransientActivation):
(TestWebKitAPI::simulateUserGesture):
(TestWebKitAPI::TEST(AsyncFunction, 
TransientActivationFromUserGestureIsPreserved)):

Canonical link: https://commits.webkit.org/321448@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to