Changeset 275187 in webkit
- Timestamp:
- Mar 29, 2021 3:55:49 PM (16 months ago)
- Location:
- trunk
- Files:
-
- 2 added
- 8 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/editing/pasteboard/dom-paste/dom-paste-requires-user-gesture.html (modified) (1 diff)
-
LayoutTests/fast/animation/request-animation-frame-propagate-user-gesture-expected.txt (added)
-
LayoutTests/fast/animation/request-animation-frame-propagate-user-gesture.html (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/dom/ScriptedAnimationController.cpp (modified) (8 diffs)
-
Source/WebCore/dom/ScriptedAnimationController.h (modified) (2 diffs)
-
Source/WebCore/testing/Internals.cpp (modified) (1 diff)
-
Source/WebCore/testing/Internals.h (modified) (1 diff)
-
Source/WebCore/testing/Internals.idl (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r275179 r275187 1 2021-03-29 Devin Rousso <drousso@apple.com> 2 3 Propagate user gestures through `requestAnimationFrame` just like `setTimeout` 4 https://bugs.webkit.org/show_bug.cgi?id=223775 5 <rdar://problem/75860868> 6 7 Reviewed by Geoffrey Garen. 8 9 * editing/pasteboard/dom-paste/dom-paste-requires-user-gesture.html: 10 * fast/animation/request-animation-frame-propagate-user-gesture.html: Added. 11 * fast/animation/request-animation-frame-propagate-user-gesture-expected.txt: Added. 12 1 13 2021-03-29 Robert Jenner <jenner@apple.com> 2 14 -
trunk/LayoutTests/editing/pasteboard/dom-paste/dom-paste-requires-user-gesture.html
r268400 r275187 55 55 editor.focus(); 56 56 shouldBe("document.execCommand('Paste')", "true"); 57 requestAnimationFrame(() => {57 internals.withoutUserGesture(() => { 58 58 shouldBe("document.execCommand('Paste')", "false") 59 59 shouldBeEqualToString("editor.textContent", "Click here to copy"); -
trunk/Source/WebCore/ChangeLog
r275185 r275187 1 2021-03-29 Devin Rousso <drousso@apple.com> 2 3 Propagate user gestures through `requestAnimationFrame` just like `setTimeout` 4 https://bugs.webkit.org/show_bug.cgi?id=223775 5 <rdar://problem/75860868> 6 7 Reviewed by Geoffrey Garen. 8 9 `setTimeout` and `requestAnimationFrame` are used somewhat interchangeably on the web. 10 There should be similar features/affordances for both so that if a developer decides to use 11 a display-linked animation "loop" instead of a strictly time-based delay (or even a "loop") 12 they're able to do similar things in the callback/handler. 13 14 Test: fast/animation/request-animation-frame-propagate-user-gesture.html 15 16 * dom/ScriptedAnimationController.h: 17 * dom/ScriptedAnimationController.cpp: 18 (WebCore::ScriptedAnimationController::resume): 19 (WebCore::ScriptedAnimationController::registerCallback): 20 (WebCore::ScriptedAnimationController::cancelCallback): 21 (WebCore::ScriptedAnimationController::serviceRequestAnimationFrameCallbacks): 22 Create a private struct for holding more data in the list of callbacks than just the 23 callback itself. For now, the only other data saved is a `RefPtr<UserGestureToken>`. 24 25 * testing/Internals.idl: 26 * testing/Internals.h: 27 * testing/Internals.cpp: 28 (WebCore::Internals::withoutUserGesture): Added. 29 Add a way for tests to guaranteed run arbitrary code without a user gesture. 30 1 31 2021-03-29 Said Abou-Hallawa <said@apple.com> 2 32 -
trunk/Source/WebCore/dom/ScriptedAnimationController.cpp
r273773 r275187 33 33 #include "RequestAnimationFrameCallback.h" 34 34 #include "Settings.h" 35 #include "UserGestureIndicator.h" 35 36 #include <wtf/Ref.h> 36 37 #include <wtf/SystemTracing.h> … … 62 63 --m_suspendCount; 63 64 64 if (!m_suspendCount && m_callback s.size())65 if (!m_suspendCount && m_callbackDataList.size()) 65 66 scheduleAnimation(); 66 67 } … … 112 113 callback->m_firedOrCancelled = false; 113 114 callback->m_id = callbackId; 114 m_callback s.append(WTFMove(callback));115 m_callbackDataList.append({ WTFMove(callback), UserGestureIndicator::currentUserGesture() }); 115 116 116 117 if (m_document) … … 124 125 void ScriptedAnimationController::cancelCallback(CallbackId callbackId) 125 126 { 126 bool cancelled = m_callback s.removeFirstMatching([callbackId](auto& callback) {127 if ( callback->m_id != callbackId)127 bool cancelled = m_callbackDataList.removeFirstMatching([callbackId](auto& data) { 128 if (data.callback->m_id != callbackId) 128 129 return false; 129 callback->m_firedOrCancelled = true;130 data.callback->m_firedOrCancelled = true; 130 131 return true; 131 132 }); … … 137 138 void ScriptedAnimationController::serviceRequestAnimationFrameCallbacks(ReducedResolutionSeconds timestamp) 138 139 { 139 if (!m_callback s.size() || m_suspendCount || !requestAnimationFrameEnabled())140 if (!m_callbackDataList.size() || m_suspendCount || !requestAnimationFrameEnabled()) 140 141 return; 141 142 … … 153 154 // First, generate a list of callbacks to consider. Callbacks registered from this point 154 155 // on are considered only for the "next" frame, not this one. 155 CallbackList callbacks(m_callbacks);156 Vector<CallbackData> callbackDataList(m_callbackDataList); 156 157 157 158 // Invoking callbacks may detach elements from our document, which clears the document's … … 160 161 Ref<Document> protectedDocument(*m_document); 161 162 162 for (auto& callback : callbacks) {163 for (auto& [callback, userGestureTokenToForward] : callbackDataList) { 163 164 if (callback->m_firedOrCancelled) 164 165 continue; 165 166 callback->m_firedOrCancelled = true; 167 168 if (userGestureTokenToForward && userGestureTokenToForward->hasExpired(UserGestureToken::maximumIntervalForUserGestureForwarding)) 169 userGestureTokenToForward = nullptr; 170 UserGestureIndicator gestureIndicator(userGestureTokenToForward); 166 171 167 172 InspectorInstrumentation::willFireAnimationFrame(protectedDocument, callback->m_id); … … 171 176 172 177 // Remove any callbacks we fired from the list of pending callbacks. 173 m_callback s.removeAllMatching([](auto& callback) {174 return callback->m_firedOrCancelled;178 m_callbackDataList.removeAllMatching([](auto& data) { 179 return data.callback->m_firedOrCancelled; 175 180 }); 176 181 177 182 m_lastAnimationFrameTimestamp = timestamp; 178 183 179 if (m_callback s.size())184 if (m_callbackDataList.size()) 180 185 scheduleAnimation(); 181 186 } -
trunk/Source/WebCore/dom/ScriptedAnimationController.h
r261113 r275187 40 40 class Page; 41 41 class RequestAnimationFrameCallback; 42 class UserGestureToken; 42 43 43 44 class ScriptedAnimationController : public RefCounted<ScriptedAnimationController> … … 75 76 void scheduleAnimation(); 76 77 77 using CallbackList = Vector<RefPtr<RequestAnimationFrameCallback>>; 78 CallbackList m_callbacks; 78 struct CallbackData { 79 Ref<RequestAnimationFrameCallback> callback; 80 RefPtr<UserGestureToken> userGestureTokenToForward; 81 }; 82 Vector<CallbackData> m_callbackDataList; 79 83 80 84 WeakPtr<Document> m_document; -
trunk/Source/WebCore/testing/Internals.cpp
r275176 r275187 4853 4853 } 4854 4854 4855 void Internals::withoutUserGesture(RefPtr<VoidCallback>&& callback) 4856 { 4857 UserGestureIndicator gestureIndicator(NotProcessingUserGesture, contextDocument()); 4858 callback->handleEvent(); 4859 } 4860 4855 4861 bool Internals::userIsInteracting() 4856 4862 { -
trunk/Source/WebCore/testing/Internals.h
r275151 r275187 746 746 747 747 void withUserGesture(RefPtr<VoidCallback>&&); 748 void withoutUserGesture(RefPtr<VoidCallback>&&); 748 749 749 750 bool userIsInteracting(); -
trunk/Source/WebCore/testing/Internals.idl
r275151 r275187 783 783 784 784 undefined withUserGesture(VoidCallback callback); 785 undefined withoutUserGesture(VoidCallback callback); 785 786 786 787 boolean userIsInteracting();
Note: See TracChangeset
for help on using the changeset viewer.