Title: [278392] trunk/Source/WebCore
Revision
278392
Author
cdu...@apple.com
Date
2021-06-02 18:54:35 -0700 (Wed, 02 Jun 2021)

Log Message

Port media code to the HTML event loop
https://bugs.webkit.org/show_bug.cgi?id=226543

Reviewed by Ryosuke Niwa.

Port media code to the HTML event loop so that event processing order is consistent
with non-media related events. To avoid having a very large patch, I made the following
changes:
- Update MainThreadGenericEventQueue to be based on the HTML event loop instead of a
  global Timer.
- Introduce a EventLoopDeferrableTask which has the same API as DeferrableTask<Timer> but
  uses the HTML event loop instead of a global Timer. Port media code to use
  EventLoopDeferrableTask instead of DeferrableTask.
- Introduce an EventLoopTaskQueue which has the same API as GenericTaskQueue<Timer>
  but uses the HTML event loop instead of a global Timer. Port media code to use
  EventLoopTaskQueue instead of GenericTaskQueue<Timer>.

This effectively ports our entire media code to the HTML event loop. It allows new
media code to use the HTML event loop *directly* without fear of ordering issues. It also
allows us to refactor existing media code to use the HTML event loop *directly* when possible,
in an incremental fashion, without causing ordering issues.

* Headers.cmake:
* Modules/remoteplayback/RemotePlayback.cpp:
(WebCore::RemotePlayback::RemotePlayback):
* Modules/remoteplayback/RemotePlayback.h:
* animation/DocumentTimelinesController.cpp:
(WebCore::DocumentTimelinesController::DocumentTimelinesController):
* animation/DocumentTimelinesController.h:
* dom/FullscreenManager.cpp:
* dom/FullscreenManager.h:
* dom/GenericEventQueue.cpp:
(WebCore::MainThreadGenericEventQueue::MainThreadGenericEventQueue):
(WebCore::MainThreadGenericEventQueue::enqueueEvent):
(WebCore::MainThreadGenericEventQueue::close):
(WebCore::MainThreadGenericEventQueue::cancelAllEvents):
(WebCore::MainThreadGenericEventQueue::hasPendingEventsOfType const):
* dom/GenericEventQueue.h:
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::HTMLMediaElement):
* html/HTMLMediaElement.h:
* html/shadow/MediaControlTextTrackContainerElement.cpp:
(WebCore::MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement):
* html/shadow/MediaControlTextTrackContainerElement.h:
* platform/DeferrableTask.h:
(WebCore::DeferrableTaskBase::close):
(WebCore::DeferrableTaskBase::cancelTask):
(WebCore::DeferrableTaskBase::hasPendingTask const):
(WebCore::DeferrableTaskBase::isClosed const):
(WebCore::DeferrableTaskBase::setHasPendingTask):
* platform/GenericTaskQueue.h:
(WebCore::GenericTaskQueueBase::hasPendingTasks const):
(WebCore::GenericTaskQueueBase::isClosed const):
(WebCore::GenericTaskQueueBase::close):
(WebCore::GenericTaskQueueBase::cancelAllTasks):
(WebCore::GenericTaskQueueBase::incrementPendingTasks):
(WebCore::GenericTaskQueueBase::decremementPendingTasks):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (278391 => 278392)


--- trunk/Source/WebCore/ChangeLog	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/ChangeLog	2021-06-03 01:54:35 UTC (rev 278392)
@@ -1,3 +1,63 @@
+2021-06-02  Chris Dumez  <cdu...@apple.com>
+
+        Port media code to the HTML event loop
+        https://bugs.webkit.org/show_bug.cgi?id=226543
+
+        Reviewed by Ryosuke Niwa.
+
+        Port media code to the HTML event loop so that event processing order is consistent
+        with non-media related events. To avoid having a very large patch, I made the following
+        changes:
+        - Update MainThreadGenericEventQueue to be based on the HTML event loop instead of a
+          global Timer.
+        - Introduce a EventLoopDeferrableTask which has the same API as DeferrableTask<Timer> but
+          uses the HTML event loop instead of a global Timer. Port media code to use
+          EventLoopDeferrableTask instead of DeferrableTask.
+        - Introduce an EventLoopTaskQueue which has the same API as GenericTaskQueue<Timer>
+          but uses the HTML event loop instead of a global Timer. Port media code to use
+          EventLoopTaskQueue instead of GenericTaskQueue<Timer>.
+
+        This effectively ports our entire media code to the HTML event loop. It allows new
+        media code to use the HTML event loop *directly* without fear of ordering issues. It also
+        allows us to refactor existing media code to use the HTML event loop *directly* when possible,
+        in an incremental fashion, without causing ordering issues.
+
+        * Headers.cmake:
+        * Modules/remoteplayback/RemotePlayback.cpp:
+        (WebCore::RemotePlayback::RemotePlayback):
+        * Modules/remoteplayback/RemotePlayback.h:
+        * animation/DocumentTimelinesController.cpp:
+        (WebCore::DocumentTimelinesController::DocumentTimelinesController):
+        * animation/DocumentTimelinesController.h:
+        * dom/FullscreenManager.cpp:
+        * dom/FullscreenManager.h:
+        * dom/GenericEventQueue.cpp:
+        (WebCore::MainThreadGenericEventQueue::MainThreadGenericEventQueue):
+        (WebCore::MainThreadGenericEventQueue::enqueueEvent):
+        (WebCore::MainThreadGenericEventQueue::close):
+        (WebCore::MainThreadGenericEventQueue::cancelAllEvents):
+        (WebCore::MainThreadGenericEventQueue::hasPendingEventsOfType const):
+        * dom/GenericEventQueue.h:
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement):
+        * html/HTMLMediaElement.h:
+        * html/shadow/MediaControlTextTrackContainerElement.cpp:
+        (WebCore::MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement):
+        * html/shadow/MediaControlTextTrackContainerElement.h:
+        * platform/DeferrableTask.h:
+        (WebCore::DeferrableTaskBase::close):
+        (WebCore::DeferrableTaskBase::cancelTask):
+        (WebCore::DeferrableTaskBase::hasPendingTask const):
+        (WebCore::DeferrableTaskBase::isClosed const):
+        (WebCore::DeferrableTaskBase::setHasPendingTask):
+        * platform/GenericTaskQueue.h:
+        (WebCore::GenericTaskQueueBase::hasPendingTasks const):
+        (WebCore::GenericTaskQueueBase::isClosed const):
+        (WebCore::GenericTaskQueueBase::close):
+        (WebCore::GenericTaskQueueBase::cancelAllTasks):
+        (WebCore::GenericTaskQueueBase::incrementPendingTasks):
+        (WebCore::GenericTaskQueueBase::decremementPendingTasks):
+
 2021-06-02  Alex Christensen  <achristen...@webkit.org>
 
         Fix WPT test resource-timing/cross-origin-redirects.html

Modified: trunk/Source/WebCore/Headers.cmake (278391 => 278392)


--- trunk/Source/WebCore/Headers.cmake	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/Headers.cmake	2021-06-03 01:54:35 UTC (rev 278392)
@@ -461,6 +461,7 @@
     dom/EventListener.h
     dom/EventListenerMap.h
     dom/EventListenerOptions.h
+    dom/EventLoop.h
     dom/EventModifierInit.h
     dom/EventNames.h
     dom/EventQueue.h

Modified: trunk/Source/WebCore/Modules/remoteplayback/RemotePlayback.cpp (278391 => 278392)


--- trunk/Source/WebCore/Modules/remoteplayback/RemotePlayback.cpp	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/Modules/remoteplayback/RemotePlayback.cpp	2021-06-03 01:54:35 UTC (rev 278392)
@@ -51,6 +51,7 @@
     : WebCore::ActiveDOMObject(element.scriptExecutionContext())
     , m_mediaElement(makeWeakPtr(element))
     , m_eventQueue(MainThreadGenericEventQueue::create(*this))
+    , m_taskQueue(element.scriptExecutionContext())
 {
     suspendIfNeeded();
 }

Modified: trunk/Source/WebCore/Modules/remoteplayback/RemotePlayback.h (278391 => 278392)


--- trunk/Source/WebCore/Modules/remoteplayback/RemotePlayback.h	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/Modules/remoteplayback/RemotePlayback.h	2021-06-03 01:54:35 UTC (rev 278392)
@@ -101,7 +101,7 @@
     bool m_available { false };
 
     UniqueRef<MainThreadGenericEventQueue> m_eventQueue;
-    GenericTaskQueue<Timer> m_taskQueue;
+    EventLoopTaskQueue m_taskQueue;
 };
 
 }

Modified: trunk/Source/WebCore/animation/DocumentTimelinesController.cpp (278391 => 278392)


--- trunk/Source/WebCore/animation/DocumentTimelinesController.cpp	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/animation/DocumentTimelinesController.cpp	2021-06-03 01:54:35 UTC (rev 278392)
@@ -43,7 +43,8 @@
 namespace WebCore {
 
 DocumentTimelinesController::DocumentTimelinesController(Document& document)
-    : m_document(document)
+    : m_currentTimeClearingTaskQueue(&document)
+    , m_document(document)
 {
     if (auto* page = document.page()) {
         if (page->settings().hiddenPageCSSAnimationSuspensionEnabled() && !page->isVisible())

Modified: trunk/Source/WebCore/animation/DocumentTimelinesController.h (278391 => 278392)


--- trunk/Source/WebCore/animation/DocumentTimelinesController.h	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/animation/DocumentTimelinesController.h	2021-06-03 01:54:35 UTC (rev 278392)
@@ -67,7 +67,7 @@
     void maybeClearCachedCurrentTime();
 
     WeakHashSet<DocumentTimeline> m_timelines;
-    GenericTaskQueue<Timer> m_currentTimeClearingTaskQueue;
+    EventLoopTaskQueue m_currentTimeClearingTaskQueue;
     Document& m_document;
     Markable<Seconds, Seconds::MarkableTraits> m_cachedCurrentTime;
     bool m_isSuspended { false };

Modified: trunk/Source/WebCore/dom/FullscreenManager.cpp (278391 => 278392)


--- trunk/Source/WebCore/dom/FullscreenManager.cpp	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/dom/FullscreenManager.cpp	2021-06-03 01:54:35 UTC (rev 278392)
@@ -48,6 +48,7 @@
 
 FullscreenManager::FullscreenManager(Document& document)
     : m_document { document }
+    , m_fullscreenTaskQueue { &document }
 #if !RELEASE_LOG_DISABLED
     , m_logIdentifier(LoggerHelper::uniqueLogIdentifier())
 #endif

Modified: trunk/Source/WebCore/dom/FullscreenManager.h (278391 => 278392)


--- trunk/Source/WebCore/dom/FullscreenManager.h	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/dom/FullscreenManager.h	2021-06-03 01:54:35 UTC (rev 278392)
@@ -119,7 +119,7 @@
     RefPtr<Element> m_fullscreenElement;
     Vector<RefPtr<Element>> m_fullscreenElementStack;
     WeakPtr<RenderFullScreen> m_fullscreenRenderer { nullptr };
-    GenericTaskQueue<Timer> m_fullscreenTaskQueue;
+    EventLoopTaskQueue m_fullscreenTaskQueue;
     Deque<RefPtr<Node>> m_fullscreenChangeEventTargetQueue;
     Deque<RefPtr<Node>> m_fullscreenErrorEventTargetQueue;
     LayoutRect m_savedPlaceholderFrameRect;

Modified: trunk/Source/WebCore/dom/GenericEventQueue.cpp (278391 => 278392)


--- trunk/Source/WebCore/dom/GenericEventQueue.cpp	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/dom/GenericEventQueue.cpp	2021-06-03 01:54:35 UTC (rev 278392)
@@ -28,10 +28,12 @@
 
 #include "Document.h"
 #include "Event.h"
+#include "EventLoop.h"
 #include "EventTarget.h"
 #include "Node.h"
 #include "ScriptExecutionContext.h"
 #include "Timer.h"
+#include <wtf/Algorithms.h>
 #include <wtf/MainThread.h>
 #include <wtf/SetForScope.h>
 
@@ -40,13 +42,12 @@
 MainThreadGenericEventQueue::MainThreadGenericEventQueue(EventTarget& owner)
     : ActiveDOMObject(owner.scriptExecutionContext())
     , m_owner(owner)
-    , m_taskQueue(makeUniqueRef<GenericTaskQueue<Timer>>())
 {
 }
 
 void MainThreadGenericEventQueue::enqueueEvent(RefPtr<Event>&& event)
 {
-    if (m_isClosed)
+    if (m_isClosed || !scriptExecutionContext())
         return;
 
     if (event->target() == &m_owner)
@@ -54,10 +55,10 @@
 
     m_pendingEvents.append(WTFMove(event));
 
-    if (isSuspendedOrPausedByClient())
-        return;
-
-    m_taskQueue->enqueueTask(std::bind(&MainThreadGenericEventQueue::dispatchOneEvent, this));
+    scriptExecutionContext()->eventLoop().queueTask(TaskSource::MediaElement, [weakThis = makeWeakPtr(*this)] {
+        if (weakThis)
+            weakThis->dispatchOneEvent();
+    });
 }
 
 void MainThreadGenericEventQueue::dispatchOneEvent()
@@ -78,14 +79,12 @@
 void MainThreadGenericEventQueue::close()
 {
     m_isClosed = true;
-
-    m_taskQueue->close();
-    m_pendingEvents.clear();
+    cancelAllEvents();
 }
 
 void MainThreadGenericEventQueue::cancelAllEvents()
 {
-    m_taskQueue->cancelAllTasks();
+    weakPtrFactory().revokeAll();
     m_pendingEvents.clear();
 }
 
@@ -96,53 +95,9 @@
 
 bool MainThreadGenericEventQueue::hasPendingEventsOfType(const AtomString& type) const
 {
-    for (auto& event : m_pendingEvents) {
-        if (event->type() == type)
-            return true;
-    }
-
-    return false;
+    return WTF::anyOf(m_pendingEvents, [&](auto& event) { return event->type() == type; });
 }
 
-void MainThreadGenericEventQueue::setPaused(bool shouldPause)
-{
-    if (m_isPausedByClient == shouldPause)
-        return;
-
-    m_isPausedByClient = shouldPause;
-    if (shouldPause)
-        m_taskQueue->cancelAllTasks();
-    else
-        rescheduleAllEventsIfNeeded();
-}
-
-void MainThreadGenericEventQueue::suspend(ReasonForSuspension)
-{
-    if (m_isSuspended)
-        return;
-
-    m_isSuspended = true;
-    m_taskQueue->cancelAllTasks();
-}
-
-void MainThreadGenericEventQueue::resume()
-{
-    if (!m_isSuspended)
-        return;
-
-    m_isSuspended = false;
-    rescheduleAllEventsIfNeeded();
-}
-
-void MainThreadGenericEventQueue::rescheduleAllEventsIfNeeded()
-{
-    if (isSuspendedOrPausedByClient())
-        return;
-
-    for (unsigned i = 0; i < m_pendingEvents.size(); ++i)
-        m_taskQueue->enqueueTask(std::bind(&MainThreadGenericEventQueue::dispatchOneEvent, this));
-}
-
 void MainThreadGenericEventQueue::stop()
 {
     close();

Modified: trunk/Source/WebCore/dom/GenericEventQueue.h (278391 => 278392)


--- trunk/Source/WebCore/dom/GenericEventQueue.h	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/dom/GenericEventQueue.h	2021-06-03 01:54:35 UTC (rev 278392)
@@ -26,22 +26,20 @@
 #pragma once
 
 #include "ActiveDOMObject.h"
-#include "GenericTaskQueue.h"
 #include <wtf/Deque.h>
 #include <wtf/Forward.h>
 #include <wtf/RefPtr.h>
 #include <wtf/UniqueRef.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 
 class Event;
 class EventTarget;
-class Timer;
 class ScriptExecutionContext;
 
-// All instances of MainThreadGenericEventQueue use a shared Timer for dispatching events.
 // FIXME: We should port call sites to the HTML event loop and remove this class.
-class MainThreadGenericEventQueue : public ActiveDOMObject {
+class MainThreadGenericEventQueue : public ActiveDOMObject, public CanMakeWeakPtr<MainThreadGenericEventQueue> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     static UniqueRef<MainThreadGenericEventQueue> create(EventTarget&);
@@ -52,10 +50,6 @@
     void cancelAllEvents();
     bool hasPendingEventsOfType(const AtomString&) const;
 
-    void setPaused(bool);
-
-    bool isSuspended() const { return m_isSuspended; }
-
     bool hasPendingActivity() const;
 
 private:
@@ -66,18 +60,10 @@
 
     const char* activeDOMObjectName() const final;
     void stop() final;
-    void suspend(ReasonForSuspension) final;
-    void resume() final;
 
-    void rescheduleAllEventsIfNeeded();
-    bool isSuspendedOrPausedByClient() const { return m_isSuspended || m_isPausedByClient; }
-
     EventTarget& m_owner;
-    UniqueRef<GenericTaskQueue<Timer>> m_taskQueue;
     Deque<RefPtr<Event>> m_pendingEvents;
     bool m_isClosed { false };
-    bool m_isPausedByClient { false };
-    bool m_isSuspended { false };
     bool m_isFiringEvent { false };
 };
 

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (278391 => 278392)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2021-06-03 01:54:35 UTC (rev 278392)
@@ -394,7 +394,21 @@
     , m_scanTimer(*this, &HTMLMediaElement::scanTimerFired)
     , m_playbackControlsManagerBehaviorRestrictionsTimer(*this, &HTMLMediaElement::playbackControlsManagerBehaviorRestrictionsTimerFired)
     , m_seekToPlaybackPositionEndedTimer(*this, &HTMLMediaElement::seekToPlaybackPositionEndedTimerFired)
+    , m_configureTextTracksTask(&document)
+    , m_checkPlaybackTargetCompatibilityTask(&document)
+    , m_updateMediaStateTask(&document)
+    , m_mediaEngineUpdatedTask(&document)
     , m_updatePlayStateTask(*this)
+    , m_resumeTask(&document)
+    , m_seekTask(&document)
+    , m_playbackControlsManagerBehaviorRestrictionsTask(&document)
+    , m_bufferedTimeRangesChangedTask(&document)
+    , m_promiseTaskQueue(&document)
+    , m_pauseAfterDetachedTaskQueue(&document)
+    , m_resourceSelectionTaskQueue(&document)
+    , m_visibilityChangeTaskQueue(&document)
+    , m_fullscreenTaskQueue(&document)
+    , m_playbackTargetIsWirelessQueue(&document)
     , m_asyncEventQueue(MainThreadGenericEventQueue::create(*this))
     , m_lastTimeUpdateEventMovieTime(MediaTime::positiveInfiniteTime())
     , m_firstTimePlaying(true)
@@ -434,6 +448,9 @@
     , m_processingPreferenceChange(false)
     , m_shouldAudioPlaybackRequireUserGesture(document.topDocument().audioPlaybackRequiresUserGesture() && !processingUserGestureForMedia())
     , m_shouldVideoPlaybackRequireUserGesture(document.topDocument().videoPlaybackRequiresUserGesture() && !processingUserGestureForMedia())
+#if ENABLE(ENCRYPTED_MEDIA)
+    , m_encryptedMediaQueue(&document)
+#endif
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     , m_remote(RemotePlayback::create(*this))
 #endif
@@ -567,11 +584,11 @@
     if (m_isolatedWorld)
         m_isolatedWorld->clearWrappers();
 
-    m_seekTaskQueue.close();
-    m_resumeTaskQueue.close();
+    m_seekTask.close();
+    m_resumeTask.close();
     m_promiseTaskQueue.close();
     m_pauseAfterDetachedTaskQueue.close();
-    m_playbackControlsManagerBehaviorRestrictionsQueue.close();
+    m_playbackControlsManagerBehaviorRestrictionsTask.close();
     m_resourceSelectionTaskQueue.close();
     m_visibilityChangeTaskQueue.close();
 #if ENABLE(ENCRYPTED_MEDIA)
@@ -980,16 +997,16 @@
 
 void HTMLMediaElement::scheduleCheckPlaybackTargetCompatability()
 {
-    if (m_checkPlaybackTargetCompatablityTask.hasPendingTask())
+    if (m_checkPlaybackTargetCompatibilityTask.isPending())
         return;
 
     ALWAYS_LOG(LOGIDENTIFIER);
-    m_checkPlaybackTargetCompatablityTask.scheduleTask([this] {
-        checkPlaybackTargetCompatablity();
+    m_checkPlaybackTargetCompatibilityTask.scheduleTask([this] {
+        checkPlaybackTargetCompatibility();
     });
 }
 
-void HTMLMediaElement::checkPlaybackTargetCompatablity()
+void HTMLMediaElement::checkPlaybackTargetCompatibility()
 {
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     if (m_isPlayingToWirelessTarget && !m_player->canPlayToWirelessPlaybackTarget()) {
@@ -2957,9 +2974,9 @@
     // 3 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
     // already running. Abort that other instance of the algorithm without waiting for the step that
     // it is running to complete.
-    if (m_seekTaskQueue.hasPendingTask()) {
+    if (m_seekTask.isPending()) {
         INFO_LOG(LOGIDENTIFIER, "cancelling pending seeks");
-        m_seekTaskQueue.cancelTask();
+        m_seekTask.cancelTask();
         if (m_pendingSeek) {
             now = m_pendingSeek->now;
             m_pendingSeek = nullptr;
@@ -2981,7 +2998,7 @@
     m_pendingSeek = makeUnique<PendingSeek>(now, time, negativeTolerance, positiveTolerance);
     if (fromDOM) {
         INFO_LOG(LOGIDENTIFIER, "enqueuing seek from ", now, " to ", time);
-        m_seekTaskQueue.scheduleTask(std::bind(&HTMLMediaElement::seekTask, this));
+        m_seekTask.scheduleTask(std::bind(&HTMLMediaElement::seekTask, this));
     } else
         seekTask();
 
@@ -3693,7 +3710,7 @@
     auto oldVolume = m_volume;
     m_volume = volume;
 
-    if (m_volumeRevertTaskQueue.hasPendingTask())
+    if (m_volumeRevertTaskQueue.isPending())
         return { };
 
     m_volumeRevertTaskQueue.scheduleTask([this, oldVolume] {
@@ -4481,7 +4498,7 @@
 
 void HTMLMediaElement::scheduleConfigureTextTracks()
 {
-    if (m_configureTextTracksTask.hasPendingTask())
+    if (m_configureTextTracksTask.isPending())
         return;
 
     auto logSiteIdentifier = LOGIDENTIFIER;
@@ -5029,7 +5046,7 @@
 
 void HTMLMediaElement::scheduleMediaEngineWasUpdated()
 {
-    if (m_mediaEngineUpdatedTask.hasPendingTask())
+    if (m_mediaEngineUpdatedTask.isPending())
         return;
 
     auto logSiteIdentifier = LOGIDENTIFIER;
@@ -5322,7 +5339,7 @@
 
 void HTMLMediaElement::scheduleUpdatePlayState()
 {
-    if (m_updatePlayStateTask.hasPendingTask())
+    if (m_updatePlayStateTask.isPending())
         return;
 
     auto logSiteIdentifier = LOGIDENTIFIER;
@@ -5460,7 +5477,7 @@
 void HTMLMediaElement::cancelPendingTasks()
 {
     m_configureTextTracksTask.cancelTask();
-    m_checkPlaybackTargetCompatablityTask.cancelTask();
+    m_checkPlaybackTargetCompatibilityTask.cancelTask();
     m_updateMediaStateTask.cancelTask();
     m_mediaEngineUpdatedTask.cancelTask();
     m_updatePlayStateTask.cancelTask();
@@ -5622,15 +5639,15 @@
 void HTMLMediaElement::closeTaskQueues()
 {
     m_configureTextTracksTask.close();
-    m_checkPlaybackTargetCompatablityTask.close();
+    m_checkPlaybackTargetCompatibilityTask.close();
     m_updateMediaStateTask.close();
     m_mediaEngineUpdatedTask.close();
     m_updatePlayStateTask.close();
-    m_resumeTaskQueue.close();
-    m_seekTaskQueue.close();
-    m_playbackControlsManagerBehaviorRestrictionsQueue.close();
-    m_seekTaskQueue.close();
-    m_resumeTaskQueue.close();
+    m_resumeTask.close();
+    m_seekTask.close();
+    m_playbackControlsManagerBehaviorRestrictionsTask.close();
+    m_seekTask.close();
+    m_resumeTask.close();
     m_promiseTaskQueue.close();
     m_pauseAfterDetachedTaskQueue.close();
     m_resourceSelectionTaskQueue.close();
@@ -5675,7 +5692,7 @@
     ALWAYS_LOG(LOGIDENTIFIER);
     Ref<HTMLMediaElement> protectedThis(*this);
 
-    m_resumeTaskQueue.cancelTask();
+    m_resumeTask.cancelTask();
 
     switch (reason) {
     case ReasonForSuspension::BackForwardCache:
@@ -5708,13 +5725,13 @@
         m_mediaSession->updateBufferingPolicy();
     }
 
-    if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED && !m_resumeTaskQueue.hasPendingTask()) {
+    if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED && !m_resumeTask.isPending()) {
         // Restart the load if it was aborted in the middle by moving the document to the back/forward cache.
         // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
         //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
         // This behavior is not specified but it seems like a sensible thing to do.
         // As it is not safe to immedately start loading now, let's schedule a load.
-        m_resumeTaskQueue.scheduleTask(std::bind(&HTMLMediaElement::prepareForLoad, this));
+        m_resumeTask.scheduleTask(std::bind(&HTMLMediaElement::prepareForLoad, this));
     }
 
     updateRenderer();
@@ -7137,12 +7154,12 @@
 
 void HTMLMediaElement::mediaPlayerBufferedTimeRangesChanged()
 {
-    if (!m_textTracks || m_bufferedTimeRangesChangedQueue.hasPendingTask())
+    if (!m_textTracks || m_bufferedTimeRangesChangedTask.isPending())
         return;
 
     auto logSiteIdentifier = LOGIDENTIFIER;
     ALWAYS_LOG(logSiteIdentifier, "task scheduled");
-    m_bufferedTimeRangesChangedQueue.scheduleTask([this, logSiteIdentifier] {
+    m_bufferedTimeRangesChangedTask.scheduleTask([this, logSiteIdentifier] {
         UNUSED_PARAM(logSiteIdentifier);
         ALWAYS_LOG(logSiteIdentifier, "lambda(), task fired");
         if (!m_player || !m_textTracks)
@@ -7768,7 +7785,7 @@
 
 void HTMLMediaElement::scheduleUpdateMediaState()
 {
-    if (m_updateMediaStateTask.hasPendingTask())
+    if (m_updateMediaStateTask.isPending())
         return;
 
     auto logSiteIdentifier = LOGIDENTIFIER;
@@ -8039,7 +8056,7 @@
 
 void HTMLMediaElement::playbackControlsManagerBehaviorRestrictionsTimerFired()
 {
-    if (m_playbackControlsManagerBehaviorRestrictionsQueue.hasPendingTask())
+    if (m_playbackControlsManagerBehaviorRestrictionsTask.isPending())
         return;
 
     if (!mediaSession().hasBehaviorRestriction(MediaElementSession::RequireUserGestureToControlControlsManager))
@@ -8046,7 +8063,7 @@
         return;
 
     RefPtr<HTMLMediaElement> protectedThis(this);
-    m_playbackControlsManagerBehaviorRestrictionsQueue.scheduleTask([protectedThis] () {
+    m_playbackControlsManagerBehaviorRestrictionsTask.scheduleTask([protectedThis] () {
         auto& mediaElementSession = protectedThis->mediaSession();
         if (protectedThis->isPlaying() || mediaElementSession.state() == PlatformMediaSession::Autoplaying || mediaElementSession.state() == PlatformMediaSession::Playing)
             return;

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (278391 => 278392)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2021-06-03 01:54:35 UTC (rev 278392)
@@ -185,7 +185,7 @@
 #endif
 
     void scheduleCheckPlaybackTargetCompatability();
-    void checkPlaybackTargetCompatablity();
+    void checkPlaybackTargetCompatibility();
     void scheduleResolvePendingPlayPromises();
     void scheduleRejectPendingPlayPromises(Ref<DOMException>&&);
     using PlayPromiseVector = Vector<DOMPromiseDeferred<void>>;
@@ -944,21 +944,21 @@
     Timer m_scanTimer;
     Timer m_playbackControlsManagerBehaviorRestrictionsTimer;
     Timer m_seekToPlaybackPositionEndedTimer;
-    DeferrableTask<Timer> m_configureTextTracksTask;
-    DeferrableTask<Timer> m_checkPlaybackTargetCompatablityTask;
-    DeferrableTask<Timer> m_updateMediaStateTask;
-    DeferrableTask<Timer> m_mediaEngineUpdatedTask;
+    EventLoopDeferrableTask m_configureTextTracksTask;
+    EventLoopDeferrableTask m_checkPlaybackTargetCompatibilityTask;
+    EventLoopDeferrableTask m_updateMediaStateTask;
+    EventLoopDeferrableTask m_mediaEngineUpdatedTask;
     DeferrableTask<HTMLMediaElement> m_updatePlayStateTask;
-    DeferrableTask<Timer> m_resumeTaskQueue;
-    DeferrableTask<Timer> m_seekTaskQueue;
-    DeferrableTask<Timer> m_playbackControlsManagerBehaviorRestrictionsQueue;
-    DeferrableTask<Timer> m_bufferedTimeRangesChangedQueue;
-    GenericTaskQueue<Timer> m_promiseTaskQueue;
-    GenericTaskQueue<Timer> m_pauseAfterDetachedTaskQueue;
-    GenericTaskQueue<Timer> m_resourceSelectionTaskQueue;
-    GenericTaskQueue<Timer> m_visibilityChangeTaskQueue;
-    GenericTaskQueue<Timer> m_fullscreenTaskQueue;
-    GenericTaskQueue<Timer> m_playbackTargetIsWirelessQueue;
+    EventLoopDeferrableTask m_resumeTask;
+    EventLoopDeferrableTask m_seekTask;
+    EventLoopDeferrableTask m_playbackControlsManagerBehaviorRestrictionsTask;
+    EventLoopDeferrableTask m_bufferedTimeRangesChangedTask;
+    EventLoopTaskQueue m_promiseTaskQueue;
+    EventLoopTaskQueue m_pauseAfterDetachedTaskQueue;
+    EventLoopTaskQueue m_resourceSelectionTaskQueue;
+    EventLoopTaskQueue m_visibilityChangeTaskQueue;
+    EventLoopTaskQueue m_fullscreenTaskQueue;
+    EventLoopTaskQueue m_playbackTargetIsWirelessQueue;
     RefPtr<TimeRanges> m_playedTimeRanges;
     UniqueRef<MainThreadGenericEventQueue> m_asyncEventQueue;
 #if PLATFORM(IOS_FAMILY)
@@ -1162,7 +1162,7 @@
     RefPtr<MediaKeys> m_mediaKeys;
     bool m_attachingMediaKeys { false };
     bool m_playbackBlockedWaitingForKey { false };
-    GenericTaskQueue<Timer> m_encryptedMediaQueue;
+    EventLoopTaskQueue m_encryptedMediaQueue;
 #endif
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)

Modified: trunk/Source/WebCore/html/shadow/MediaControlTextTrackContainerElement.cpp (278391 => 278392)


--- trunk/Source/WebCore/html/shadow/MediaControlTextTrackContainerElement.cpp	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/html/shadow/MediaControlTextTrackContainerElement.cpp	2021-06-03 01:54:35 UTC (rev 278392)
@@ -75,6 +75,7 @@
 
 MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document& document, HTMLMediaElement& element)
     : HTMLDivElement(divTag, document)
+    , m_taskQueue(&document)
     , m_mediaElement(makeWeakPtr(&element))
 {
 }

Modified: trunk/Source/WebCore/html/shadow/MediaControlTextTrackContainerElement.h (278391 => 278392)


--- trunk/Source/WebCore/html/shadow/MediaControlTextTrackContainerElement.h	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/html/shadow/MediaControlTextTrackContainerElement.h	2021-06-03 01:54:35 UTC (rev 278392)
@@ -97,7 +97,7 @@
 
     std::unique_ptr<TextTrackRepresentation> m_textTrackRepresentation;
 
-    GenericTaskQueue<Timer> m_taskQueue;
+    EventLoopTaskQueue m_taskQueue;
     WeakPtr<HTMLMediaElement> m_mediaElement;
     IntRect m_videoDisplaySize;
     int m_fontSize { 0 };

Modified: trunk/Source/WebCore/platform/DeferrableTask.h (278391 => 278392)


--- trunk/Source/WebCore/platform/DeferrableTask.h	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/platform/DeferrableTask.h	2021-06-03 01:54:35 UTC (rev 278392)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2018-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,59 +25,95 @@
 
 #pragma once
 
+#include "ContextDestructionObserver.h"
+#include "EventLoop.h"
 #include "GenericTaskQueue.h"
+#include "ScriptExecutionContext.h"
 
 namespace WebCore {
 
+class DeferrableTaskBase : public CanMakeWeakPtr<DeferrableTaskBase> {
+public:
+    void close()
+    {
+        cancelTask();
+        m_isClosed = true;
+    }
+
+    void cancelTask()
+    {
+        weakPtrFactory().revokeAll();
+        m_isPending = false;
+    }
+
+    bool isPending() const { return m_isPending; }
+
+protected:
+    ~DeferrableTaskBase() = default;
+    bool isClosed() const { return m_isClosed; }
+    void setIsPending(bool isPending) { m_isPending = isPending; }
+
+private:
+    bool m_isPending { false };
+    bool m_isClosed { false };
+};
+
 template <typename T>
-class DeferrableTask : public CanMakeWeakPtr<DeferrableTask<T>> {
+class DeferrableTask : public DeferrableTaskBase {
 public:
     DeferrableTask()
         : m_dispatcher()
-    {
-    }
+    { }
 
     DeferrableTask(T& t)
         : m_dispatcher(&t)
-    {
-    }
+    { }
 
-    typedef WTF::Function<void ()> TaskFunction;
-
-    void scheduleTask(TaskFunction&& task)
+    void scheduleTask(Function<void()>&& task)
     {
-        if (m_isClosed)
+        if (isClosed())
             return;
 
         cancelTask();
 
-        m_pendingTask = true;
+        setIsPending(true);
         m_dispatcher.postTask([weakThis = makeWeakPtr(*this), task = WTFMove(task)] {
             if (!weakThis)
                 return;
-            ASSERT(weakThis->m_pendingTask);
-            weakThis->m_pendingTask = false;
+            ASSERT(weakThis->isPending());
+            weakThis->setIsPending(false);
             task();
         });
     }
 
-    void close()
+private:
+    TaskDispatcher<T> m_dispatcher;
+};
+
+// Similar to DeferrableTask but based on the HTML event loop.
+class EventLoopDeferrableTask : public DeferrableTaskBase, private ContextDestructionObserver {
+public:
+    EventLoopDeferrableTask(ScriptExecutionContext* context)
+        : ContextDestructionObserver(context)
+    { }
+
+    // FIXME: Pass TaskSource instead of assuming TaskSource::MediaElement.
+    void scheduleTask(Function<void()>&& task)
     {
+        if (isClosed() || !scriptExecutionContext())
+            return;
+
         cancelTask();
-        m_isClosed = true;
-    }
 
-    void cancelTask()
-    {
-        CanMakeWeakPtr<DeferrableTask<T>>::weakPtrFactory().revokeAll();
-        m_pendingTask = false;
+        setIsPending(true);
+        scriptExecutionContext()->eventLoop().queueTask(TaskSource::MediaElement, [weakThis = makeWeakPtr(*this), task = WTFMove(task)] {
+            if (!weakThis)
+                return;
+            ASSERT(weakThis->isPending());
+            weakThis->setIsPending(false);
+            task();
+        });
     }
-    bool hasPendingTask() const { return m_pendingTask; }
-
-private:
-    TaskDispatcher<T> m_dispatcher;
-    bool m_pendingTask { false };
-    bool m_isClosed { false };
 };
 
 }

Modified: trunk/Source/WebCore/platform/GenericTaskQueue.h (278391 => 278392)


--- trunk/Source/WebCore/platform/GenericTaskQueue.h	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/platform/GenericTaskQueue.h	2021-06-03 01:54:35 UTC (rev 278392)
@@ -25,6 +25,9 @@
 
 #pragma once
 
+#include "ContextDestructionObserver.h"
+#include "EventLoop.h"
+#include "ScriptExecutionContext.h"
 #include "Timer.h"
 #include <wtf/Deque.h>
 #include <wtf/Function.h>
@@ -75,8 +78,35 @@
     Deque<Function<void()>> m_pendingTasks WTF_GUARDED_BY_LOCK(s_sharedLock);
 };
 
+class GenericTaskQueueBase : public CanMakeWeakPtr<GenericTaskQueueBase> {
+public:
+    bool hasPendingTasks() const { return m_pendingTasks; }
+    bool isClosed() const { return m_isClosed; }
+
+    void close()
+    {
+        cancelAllTasks();
+        m_isClosed = true;
+    }
+
+    void cancelAllTasks()
+    {
+        weakPtrFactory().revokeAll();
+        m_pendingTasks = 0;
+    }
+
+protected:
+    ~GenericTaskQueueBase() = default;
+    void incrementPendingTasks() { ++m_pendingTasks; }
+    void decrementPendingTasks() { ASSERT(m_pendingTasks); --m_pendingTasks; }
+
+private:
+    unsigned m_pendingTasks { 0 };
+    bool m_isClosed { false };
+};
+
 template <typename T>
-class GenericTaskQueue : public CanMakeWeakPtr<GenericTaskQueue<T>> {
+class GenericTaskQueue : public GenericTaskQueueBase {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     GenericTaskQueue()
@@ -93,9 +123,10 @@
 
     explicit GenericTaskQueue(T* t)
         : m_dispatcher(makeUniqueRef<TaskDispatcher<T>>(t))
-        , m_isClosed(!t)
     {
         ASSERT(isMainThread());
+        if (!t)
+            close();
     }
 
     ~GenericTaskQueue()
@@ -104,42 +135,45 @@
             m_dispatcher->postTask([dispatcher = WTFMove(m_dispatcher)] { });
     }
 
-    typedef WTF::Function<void ()> TaskFunction;
-
-    void enqueueTask(TaskFunction&& task)
+    void enqueueTask(Function<void()>&& task)
     {
-        if (m_isClosed)
+        if (isClosed())
             return;
 
-        ++m_pendingTasks;
+        incrementPendingTasks();
         m_dispatcher->postTask([weakThis = makeWeakPtr(*this), task = WTFMove(task)] {
             if (!weakThis)
                 return;
-            ASSERT(weakThis->m_pendingTasks);
-            --weakThis->m_pendingTasks;
+            weakThis->decrementPendingTasks();
             task();
         });
     }
 
-    void close()
+private:
+    UniqueRef<TaskDispatcher<T>> m_dispatcher;
+};
+
+// Similar to GenericTaskQueue but based on the HTML event loop.
+class EventLoopTaskQueue : public GenericTaskQueueBase, private ContextDestructionObserver {
+public:
+    EventLoopTaskQueue(ScriptExecutionContext* context)
+        : ContextDestructionObserver(context)
+    { }
+
+    // FIXME: Pass a TaskSource instead of assuming TaskSource::MediaElement.
+    void enqueueTask(Function<void()>&& task)
     {
-        cancelAllTasks();
-        m_isClosed = true;
-    }
+        if (isClosed() || !scriptExecutionContext())
+            return;
 
-    void cancelAllTasks()
-    {
-        CanMakeWeakPtr<GenericTaskQueue<T>>::weakPtrFactory().revokeAll();
-        m_pendingTasks = 0;
+        incrementPendingTasks();
+        scriptExecutionContext()->eventLoop().queueTask(TaskSource::MediaElement, [weakThis = makeWeakPtr(*this), task = WTFMove(task)] {
+            if (!weakThis)
+                return;
+            weakThis->decrementPendingTasks();
+            task();
+        });
     }
-
-    bool hasPendingTasks() const { return m_pendingTasks; }
-    bool isClosed() const { return m_isClosed; }
-
-private:
-    UniqueRef<TaskDispatcher<T>> m_dispatcher;
-    unsigned m_pendingTasks { 0 };
-    bool m_isClosed { false };
 };
 
 }

Modified: trunk/Source/WebCore/platform/RemoteCommandListener.cpp (278391 => 278392)


--- trunk/Source/WebCore/platform/RemoteCommandListener.cpp	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/platform/RemoteCommandListener.cpp	2021-06-03 01:54:35 UTC (rev 278392)
@@ -71,7 +71,7 @@
 
 void RemoteCommandListener::scheduleSupportedCommandsUpdate()
 {
-    if (!m_updateCommandsTask.hasPendingTask()) {
+    if (!m_updateCommandsTask.isPending()) {
         m_updateCommandsTask.scheduleTask([this] ()  {
             updateSupportedCommands();
         });

Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm (278391 => 278392)


--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm	2021-06-03 01:54:35 UTC (rev 278392)
@@ -183,7 +183,7 @@
         return;
     }
 
-    ASSERT(!m_mappingCallback && !m_mappingCallbackTask.hasPendingTask());
+    ASSERT(!m_mappingCallback && !m_mappingCallbackTask.isPending());
 
     // An existing callback means this buffer is in the mapped state.
     m_mappingCallback = PendingMappingCallback::create(WTFMove(callback));

Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUQueueMetal.mm (278391 => 278392)


--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUQueueMetal.mm	2021-06-03 01:25:53 UTC (rev 278391)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUQueueMetal.mm	2021-06-03 01:54:35 UTC (rev 278392)
@@ -96,7 +96,7 @@
         END_BLOCK_OBJC_EXCEPTIONS
     }
 
-    if (m_presentTask.hasPendingTask() || !m_device || !m_device->swapChain())
+    if (m_presentTask.isPending() || !m_device || !m_device->swapChain())
         return;
 
     // If a GPUSwapChain exists, ensure that a present is scheduled after all command buffers.
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to