⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 278392 in webkit


Ignore:
Timestamp:
Jun 2, 2021, 6:54:35 PM (5 years ago)
Author:
Chris Dumez
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):

Location:
trunk/Source/WebCore
Files:
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r278391 r278392  
     12021-06-02  Chris Dumez  <cdumez@apple.com>
     2
     3        Port media code to the HTML event loop
     4        https://bugs.webkit.org/show_bug.cgi?id=226543
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Port media code to the HTML event loop so that event processing order is consistent
     9        with non-media related events. To avoid having a very large patch, I made the following
     10        changes:
     11        - Update MainThreadGenericEventQueue to be based on the HTML event loop instead of a
     12          global Timer.
     13        - Introduce a EventLoopDeferrableTask which has the same API as DeferrableTask<Timer> but
     14          uses the HTML event loop instead of a global Timer. Port media code to use
     15          EventLoopDeferrableTask instead of DeferrableTask.
     16        - Introduce an EventLoopTaskQueue which has the same API as GenericTaskQueue<Timer>
     17          but uses the HTML event loop instead of a global Timer. Port media code to use
     18          EventLoopTaskQueue instead of GenericTaskQueue<Timer>.
     19
     20        This effectively ports our entire media code to the HTML event loop. It allows new
     21        media code to use the HTML event loop *directly* without fear of ordering issues. It also
     22        allows us to refactor existing media code to use the HTML event loop *directly* when possible,
     23        in an incremental fashion, without causing ordering issues.
     24
     25        * Headers.cmake:
     26        * Modules/remoteplayback/RemotePlayback.cpp:
     27        (WebCore::RemotePlayback::RemotePlayback):
     28        * Modules/remoteplayback/RemotePlayback.h:
     29        * animation/DocumentTimelinesController.cpp:
     30        (WebCore::DocumentTimelinesController::DocumentTimelinesController):
     31        * animation/DocumentTimelinesController.h:
     32        * dom/FullscreenManager.cpp:
     33        * dom/FullscreenManager.h:
     34        * dom/GenericEventQueue.cpp:
     35        (WebCore::MainThreadGenericEventQueue::MainThreadGenericEventQueue):
     36        (WebCore::MainThreadGenericEventQueue::enqueueEvent):
     37        (WebCore::MainThreadGenericEventQueue::close):
     38        (WebCore::MainThreadGenericEventQueue::cancelAllEvents):
     39        (WebCore::MainThreadGenericEventQueue::hasPendingEventsOfType const):
     40        * dom/GenericEventQueue.h:
     41        * html/HTMLMediaElement.cpp:
     42        (WebCore::HTMLMediaElement::HTMLMediaElement):
     43        * html/HTMLMediaElement.h:
     44        * html/shadow/MediaControlTextTrackContainerElement.cpp:
     45        (WebCore::MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement):
     46        * html/shadow/MediaControlTextTrackContainerElement.h:
     47        * platform/DeferrableTask.h:
     48        (WebCore::DeferrableTaskBase::close):
     49        (WebCore::DeferrableTaskBase::cancelTask):
     50        (WebCore::DeferrableTaskBase::hasPendingTask const):
     51        (WebCore::DeferrableTaskBase::isClosed const):
     52        (WebCore::DeferrableTaskBase::setHasPendingTask):
     53        * platform/GenericTaskQueue.h:
     54        (WebCore::GenericTaskQueueBase::hasPendingTasks const):
     55        (WebCore::GenericTaskQueueBase::isClosed const):
     56        (WebCore::GenericTaskQueueBase::close):
     57        (WebCore::GenericTaskQueueBase::cancelAllTasks):
     58        (WebCore::GenericTaskQueueBase::incrementPendingTasks):
     59        (WebCore::GenericTaskQueueBase::decremementPendingTasks):
     60
    1612021-06-02  Alex Christensen  <achristensen@webkit.org>
    262
  • trunk/Source/WebCore/Headers.cmake

    r278391 r278392  
    462462    dom/EventListenerMap.h
    463463    dom/EventListenerOptions.h
     464    dom/EventLoop.h
    464465    dom/EventModifierInit.h
    465466    dom/EventNames.h
  • trunk/Source/WebCore/Modules/remoteplayback/RemotePlayback.cpp

    r278253 r278392  
    5252    , m_mediaElement(makeWeakPtr(element))
    5353    , m_eventQueue(MainThreadGenericEventQueue::create(*this))
     54    , m_taskQueue(element.scriptExecutionContext())
    5455{
    5556    suspendIfNeeded();
  • trunk/Source/WebCore/Modules/remoteplayback/RemotePlayback.h

    r278253 r278392  
    102102
    103103    UniqueRef<MainThreadGenericEventQueue> m_eventQueue;
    104     GenericTaskQueue<Timer> m_taskQueue;
     104    EventLoopTaskQueue m_taskQueue;
    105105};
    106106
  • trunk/Source/WebCore/animation/DocumentTimelinesController.cpp

    r278253 r278392  
    4444
    4545DocumentTimelinesController::DocumentTimelinesController(Document& document)
    46     : m_document(document)
     46    : m_currentTimeClearingTaskQueue(&document)
     47    , m_document(document)
    4748{
    4849    if (auto* page = document.page()) {
  • trunk/Source/WebCore/animation/DocumentTimelinesController.h

    r278253 r278392  
    6868
    6969    WeakHashSet<DocumentTimeline> m_timelines;
    70     GenericTaskQueue<Timer> m_currentTimeClearingTaskQueue;
     70    EventLoopTaskQueue m_currentTimeClearingTaskQueue;
    7171    Document& m_document;
    7272    Markable<Seconds, Seconds::MarkableTraits> m_cachedCurrentTime;
  • trunk/Source/WebCore/dom/FullscreenManager.cpp

    r274588 r278392  
    4949FullscreenManager::FullscreenManager(Document& document)
    5050    : m_document { document }
     51    , m_fullscreenTaskQueue { &document }
    5152#if !RELEASE_LOG_DISABLED
    5253    , m_logIdentifier(LoggerHelper::uniqueLogIdentifier())
  • trunk/Source/WebCore/dom/FullscreenManager.h

    r276880 r278392  
    120120    Vector<RefPtr<Element>> m_fullscreenElementStack;
    121121    WeakPtr<RenderFullScreen> m_fullscreenRenderer { nullptr };
    122     GenericTaskQueue<Timer> m_fullscreenTaskQueue;
     122    EventLoopTaskQueue m_fullscreenTaskQueue;
    123123    Deque<RefPtr<Node>> m_fullscreenChangeEventTargetQueue;
    124124    Deque<RefPtr<Node>> m_fullscreenErrorEventTargetQueue;
  • trunk/Source/WebCore/dom/GenericEventQueue.cpp

    r269321 r278392  
    2929#include "Document.h"
    3030#include "Event.h"
     31#include "EventLoop.h"
    3132#include "EventTarget.h"
    3233#include "Node.h"
    3334#include "ScriptExecutionContext.h"
    3435#include "Timer.h"
     36#include <wtf/Algorithms.h>
    3537#include <wtf/MainThread.h>
    3638#include <wtf/SetForScope.h>
     
    4143    : ActiveDOMObject(owner.scriptExecutionContext())
    4244    , m_owner(owner)
    43     , m_taskQueue(makeUniqueRef<GenericTaskQueue<Timer>>())
    4445{
    4546}
     
    4748void MainThreadGenericEventQueue::enqueueEvent(RefPtr<Event>&& event)
    4849{
    49     if (m_isClosed)
     50    if (m_isClosed || !scriptExecutionContext())
    5051        return;
    5152
     
    5556    m_pendingEvents.append(WTFMove(event));
    5657
    57     if (isSuspendedOrPausedByClient())
    58         return;
    59 
    60     m_taskQueue->enqueueTask(std::bind(&MainThreadGenericEventQueue::dispatchOneEvent, this));
     58    scriptExecutionContext()->eventLoop().queueTask(TaskSource::MediaElement, [weakThis = makeWeakPtr(*this)] {
     59        if (weakThis)
     60            weakThis->dispatchOneEvent();
     61    });
    6162}
    6263
     
    7980{
    8081    m_isClosed = true;
    81 
    82     m_taskQueue->close();
    83     m_pendingEvents.clear();
     82    cancelAllEvents();
    8483}
    8584
    8685void MainThreadGenericEventQueue::cancelAllEvents()
    8786{
    88     m_taskQueue->cancelAllTasks();
     87    weakPtrFactory().revokeAll();
    8988    m_pendingEvents.clear();
    9089}
     
    9796bool MainThreadGenericEventQueue::hasPendingEventsOfType(const AtomString& type) const
    9897{
    99     for (auto& event : m_pendingEvents) {
    100         if (event->type() == type)
    101             return true;
    102     }
    103 
    104     return false;
    105 }
    106 
    107 void MainThreadGenericEventQueue::setPaused(bool shouldPause)
    108 {
    109     if (m_isPausedByClient == shouldPause)
    110         return;
    111 
    112     m_isPausedByClient = shouldPause;
    113     if (shouldPause)
    114         m_taskQueue->cancelAllTasks();
    115     else
    116         rescheduleAllEventsIfNeeded();
    117 }
    118 
    119 void MainThreadGenericEventQueue::suspend(ReasonForSuspension)
    120 {
    121     if (m_isSuspended)
    122         return;
    123 
    124     m_isSuspended = true;
    125     m_taskQueue->cancelAllTasks();
    126 }
    127 
    128 void MainThreadGenericEventQueue::resume()
    129 {
    130     if (!m_isSuspended)
    131         return;
    132 
    133     m_isSuspended = false;
    134     rescheduleAllEventsIfNeeded();
    135 }
    136 
    137 void MainThreadGenericEventQueue::rescheduleAllEventsIfNeeded()
    138 {
    139     if (isSuspendedOrPausedByClient())
    140         return;
    141 
    142     for (unsigned i = 0; i < m_pendingEvents.size(); ++i)
    143         m_taskQueue->enqueueTask(std::bind(&MainThreadGenericEventQueue::dispatchOneEvent, this));
     98    return WTF::anyOf(m_pendingEvents, [&](auto& event) { return event->type() == type; });
    14499}
    145100
  • trunk/Source/WebCore/dom/GenericEventQueue.h

    r259299 r278392  
    2727
    2828#include "ActiveDOMObject.h"
    29 #include "GenericTaskQueue.h"
    3029#include <wtf/Deque.h>
    3130#include <wtf/Forward.h>
    3231#include <wtf/RefPtr.h>
    3332#include <wtf/UniqueRef.h>
     33#include <wtf/WeakPtr.h>
    3434
    3535namespace WebCore {
     
    3737class Event;
    3838class EventTarget;
    39 class Timer;
    4039class ScriptExecutionContext;
    4140
    42 // All instances of MainThreadGenericEventQueue use a shared Timer for dispatching events.
    4341// FIXME: We should port call sites to the HTML event loop and remove this class.
    44 class MainThreadGenericEventQueue : public ActiveDOMObject {
     42class MainThreadGenericEventQueue : public ActiveDOMObject, public CanMakeWeakPtr<MainThreadGenericEventQueue> {
    4543    WTF_MAKE_FAST_ALLOCATED;
    4644public:
     
    5250    void cancelAllEvents();
    5351    bool hasPendingEventsOfType(const AtomString&) const;
    54 
    55     void setPaused(bool);
    56 
    57     bool isSuspended() const { return m_isSuspended; }
    5852
    5953    bool hasPendingActivity() const;
     
    6761    const char* activeDOMObjectName() const final;
    6862    void stop() final;
    69     void suspend(ReasonForSuspension) final;
    70     void resume() final;
    71 
    72     void rescheduleAllEventsIfNeeded();
    73     bool isSuspendedOrPausedByClient() const { return m_isSuspended || m_isPausedByClient; }
    7463
    7564    EventTarget& m_owner;
    76     UniqueRef<GenericTaskQueue<Timer>> m_taskQueue;
    7765    Deque<RefPtr<Event>> m_pendingEvents;
    7866    bool m_isClosed { false };
    79     bool m_isPausedByClient { false };
    80     bool m_isSuspended { false };
    8167    bool m_isFiringEvent { false };
    8268};
  • trunk/Source/WebCore/html/HTMLMediaElement.cpp

    r278359 r278392  
    395395    , m_playbackControlsManagerBehaviorRestrictionsTimer(*this, &HTMLMediaElement::playbackControlsManagerBehaviorRestrictionsTimerFired)
    396396    , m_seekToPlaybackPositionEndedTimer(*this, &HTMLMediaElement::seekToPlaybackPositionEndedTimerFired)
     397    , m_configureTextTracksTask(&document)
     398    , m_checkPlaybackTargetCompatibilityTask(&document)
     399    , m_updateMediaStateTask(&document)
     400    , m_mediaEngineUpdatedTask(&document)
    397401    , m_updatePlayStateTask(*this)
     402    , m_resumeTask(&document)
     403    , m_seekTask(&document)
     404    , m_playbackControlsManagerBehaviorRestrictionsTask(&document)
     405    , m_bufferedTimeRangesChangedTask(&document)
     406    , m_promiseTaskQueue(&document)
     407    , m_pauseAfterDetachedTaskQueue(&document)
     408    , m_resourceSelectionTaskQueue(&document)
     409    , m_visibilityChangeTaskQueue(&document)
     410    , m_fullscreenTaskQueue(&document)
     411    , m_playbackTargetIsWirelessQueue(&document)
    398412    , m_asyncEventQueue(MainThreadGenericEventQueue::create(*this))
    399413    , m_lastTimeUpdateEventMovieTime(MediaTime::positiveInfiniteTime())
     
    435449    , m_shouldAudioPlaybackRequireUserGesture(document.topDocument().audioPlaybackRequiresUserGesture() && !processingUserGestureForMedia())
    436450    , m_shouldVideoPlaybackRequireUserGesture(document.topDocument().videoPlaybackRequiresUserGesture() && !processingUserGestureForMedia())
     451#if ENABLE(ENCRYPTED_MEDIA)
     452    , m_encryptedMediaQueue(&document)
     453#endif
    437454#if ENABLE(WIRELESS_PLAYBACK_TARGET)
    438455    , m_remote(RemotePlayback::create(*this))
     
    568585        m_isolatedWorld->clearWrappers();
    569586
    570     m_seekTaskQueue.close();
    571     m_resumeTaskQueue.close();
     587    m_seekTask.close();
     588    m_resumeTask.close();
    572589    m_promiseTaskQueue.close();
    573590    m_pauseAfterDetachedTaskQueue.close();
    574     m_playbackControlsManagerBehaviorRestrictionsQueue.close();
     591    m_playbackControlsManagerBehaviorRestrictionsTask.close();
    575592    m_resourceSelectionTaskQueue.close();
    576593    m_visibilityChangeTaskQueue.close();
     
    981998void HTMLMediaElement::scheduleCheckPlaybackTargetCompatability()
    982999{
    983     if (m_checkPlaybackTargetCompatablityTask.hasPendingTask())
     1000    if (m_checkPlaybackTargetCompatibilityTask.isPending())
    9841001        return;
    9851002
    9861003    ALWAYS_LOG(LOGIDENTIFIER);
    987     m_checkPlaybackTargetCompatablityTask.scheduleTask([this] {
    988         checkPlaybackTargetCompatablity();
     1004    m_checkPlaybackTargetCompatibilityTask.scheduleTask([this] {
     1005        checkPlaybackTargetCompatibility();
    9891006    });
    9901007}
    9911008
    992 void HTMLMediaElement::checkPlaybackTargetCompatablity()
     1009void HTMLMediaElement::checkPlaybackTargetCompatibility()
    9931010{
    9941011#if ENABLE(WIRELESS_PLAYBACK_TARGET)
     
    29582975    // already running. Abort that other instance of the algorithm without waiting for the step that
    29592976    // it is running to complete.
    2960     if (m_seekTaskQueue.hasPendingTask()) {
     2977    if (m_seekTask.isPending()) {
    29612978        INFO_LOG(LOGIDENTIFIER, "cancelling pending seeks");
    2962         m_seekTaskQueue.cancelTask();
     2979        m_seekTask.cancelTask();
    29632980        if (m_pendingSeek) {
    29642981            now = m_pendingSeek->now;
     
    29822999    if (fromDOM) {
    29833000        INFO_LOG(LOGIDENTIFIER, "enqueuing seek from ", now, " to ", time);
    2984         m_seekTaskQueue.scheduleTask(std::bind(&HTMLMediaElement::seekTask, this));
     3001        m_seekTask.scheduleTask(std::bind(&HTMLMediaElement::seekTask, this));
    29853002    } else
    29863003        seekTask();
     
    36943711    m_volume = volume;
    36953712
    3696     if (m_volumeRevertTaskQueue.hasPendingTask())
     3713    if (m_volumeRevertTaskQueue.isPending())
    36973714        return { };
    36983715
     
    44824499void HTMLMediaElement::scheduleConfigureTextTracks()
    44834500{
    4484     if (m_configureTextTracksTask.hasPendingTask())
     4501    if (m_configureTextTracksTask.isPending())
    44854502        return;
    44864503
     
    50305047void HTMLMediaElement::scheduleMediaEngineWasUpdated()
    50315048{
    5032     if (m_mediaEngineUpdatedTask.hasPendingTask())
     5049    if (m_mediaEngineUpdatedTask.isPending())
    50335050        return;
    50345051
     
    53235340void HTMLMediaElement::scheduleUpdatePlayState()
    53245341{
    5325     if (m_updatePlayStateTask.hasPendingTask())
     5342    if (m_updatePlayStateTask.isPending())
    53265343        return;
    53275344
     
    54615478{
    54625479    m_configureTextTracksTask.cancelTask();
    5463     m_checkPlaybackTargetCompatablityTask.cancelTask();
     5480    m_checkPlaybackTargetCompatibilityTask.cancelTask();
    54645481    m_updateMediaStateTask.cancelTask();
    54655482    m_mediaEngineUpdatedTask.cancelTask();
     
    56235640{
    56245641    m_configureTextTracksTask.close();
    5625     m_checkPlaybackTargetCompatablityTask.close();
     5642    m_checkPlaybackTargetCompatibilityTask.close();
    56265643    m_updateMediaStateTask.close();
    56275644    m_mediaEngineUpdatedTask.close();
    56285645    m_updatePlayStateTask.close();
    5629     m_resumeTaskQueue.close();
    5630     m_seekTaskQueue.close();
    5631     m_playbackControlsManagerBehaviorRestrictionsQueue.close();
    5632     m_seekTaskQueue.close();
    5633     m_resumeTaskQueue.close();
     5646    m_resumeTask.close();
     5647    m_seekTask.close();
     5648    m_playbackControlsManagerBehaviorRestrictionsTask.close();
     5649    m_seekTask.close();
     5650    m_resumeTask.close();
    56345651    m_promiseTaskQueue.close();
    56355652    m_pauseAfterDetachedTaskQueue.close();
     
    56765693    Ref<HTMLMediaElement> protectedThis(*this);
    56775694
    5678     m_resumeTaskQueue.cancelTask();
     5695    m_resumeTask.cancelTask();
    56795696
    56805697    switch (reason) {
     
    57095726    }
    57105727
    5711     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED && !m_resumeTaskQueue.hasPendingTask()) {
     5728    if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED && !m_resumeTask.isPending()) {
    57125729        // Restart the load if it was aborted in the middle by moving the document to the back/forward cache.
    57135730        // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
     
    57155732        // This behavior is not specified but it seems like a sensible thing to do.
    57165733        // As it is not safe to immedately start loading now, let's schedule a load.
    5717         m_resumeTaskQueue.scheduleTask(std::bind(&HTMLMediaElement::prepareForLoad, this));
     5734        m_resumeTask.scheduleTask(std::bind(&HTMLMediaElement::prepareForLoad, this));
    57185735    }
    57195736
     
    71387155void HTMLMediaElement::mediaPlayerBufferedTimeRangesChanged()
    71397156{
    7140     if (!m_textTracks || m_bufferedTimeRangesChangedQueue.hasPendingTask())
     7157    if (!m_textTracks || m_bufferedTimeRangesChangedTask.isPending())
    71417158        return;
    71427159
    71437160    auto logSiteIdentifier = LOGIDENTIFIER;
    71447161    ALWAYS_LOG(logSiteIdentifier, "task scheduled");
    7145     m_bufferedTimeRangesChangedQueue.scheduleTask([this, logSiteIdentifier] {
     7162    m_bufferedTimeRangesChangedTask.scheduleTask([this, logSiteIdentifier] {
    71467163        UNUSED_PARAM(logSiteIdentifier);
    71477164        ALWAYS_LOG(logSiteIdentifier, "lambda(), task fired");
     
    77697786void HTMLMediaElement::scheduleUpdateMediaState()
    77707787{
    7771     if (m_updateMediaStateTask.hasPendingTask())
     7788    if (m_updateMediaStateTask.isPending())
    77727789        return;
    77737790
     
    80408057void HTMLMediaElement::playbackControlsManagerBehaviorRestrictionsTimerFired()
    80418058{
    8042     if (m_playbackControlsManagerBehaviorRestrictionsQueue.hasPendingTask())
     8059    if (m_playbackControlsManagerBehaviorRestrictionsTask.isPending())
    80438060        return;
    80448061
     
    80478064
    80488065    RefPtr<HTMLMediaElement> protectedThis(this);
    8049     m_playbackControlsManagerBehaviorRestrictionsQueue.scheduleTask([protectedThis] () {
     8066    m_playbackControlsManagerBehaviorRestrictionsTask.scheduleTask([protectedThis] () {
    80508067        auto& mediaElementSession = protectedThis->mediaSession();
    80518068        if (protectedThis->isPlaying() || mediaElementSession.state() == PlatformMediaSession::Autoplaying || mediaElementSession.state() == PlatformMediaSession::Playing)
  • trunk/Source/WebCore/html/HTMLMediaElement.h

    r278359 r278392  
    186186
    187187    void scheduleCheckPlaybackTargetCompatability();
    188     void checkPlaybackTargetCompatablity();
     188    void checkPlaybackTargetCompatibility();
    189189    void scheduleResolvePendingPlayPromises();
    190190    void scheduleRejectPendingPlayPromises(Ref<DOMException>&&);
     
    945945    Timer m_playbackControlsManagerBehaviorRestrictionsTimer;
    946946    Timer m_seekToPlaybackPositionEndedTimer;
    947     DeferrableTask<Timer> m_configureTextTracksTask;
    948     DeferrableTask<Timer> m_checkPlaybackTargetCompatablityTask;
    949     DeferrableTask<Timer> m_updateMediaStateTask;
    950     DeferrableTask<Timer> m_mediaEngineUpdatedTask;
     947    EventLoopDeferrableTask m_configureTextTracksTask;
     948    EventLoopDeferrableTask m_checkPlaybackTargetCompatibilityTask;
     949    EventLoopDeferrableTask m_updateMediaStateTask;
     950    EventLoopDeferrableTask m_mediaEngineUpdatedTask;
    951951    DeferrableTask<HTMLMediaElement> m_updatePlayStateTask;
    952     DeferrableTask<Timer> m_resumeTaskQueue;
    953     DeferrableTask<Timer> m_seekTaskQueue;
    954     DeferrableTask<Timer> m_playbackControlsManagerBehaviorRestrictionsQueue;
    955     DeferrableTask<Timer> m_bufferedTimeRangesChangedQueue;
    956     GenericTaskQueue<Timer> m_promiseTaskQueue;
    957     GenericTaskQueue<Timer> m_pauseAfterDetachedTaskQueue;
    958     GenericTaskQueue<Timer> m_resourceSelectionTaskQueue;
    959     GenericTaskQueue<Timer> m_visibilityChangeTaskQueue;
    960     GenericTaskQueue<Timer> m_fullscreenTaskQueue;
    961     GenericTaskQueue<Timer> m_playbackTargetIsWirelessQueue;
     952    EventLoopDeferrableTask m_resumeTask;
     953    EventLoopDeferrableTask m_seekTask;
     954    EventLoopDeferrableTask m_playbackControlsManagerBehaviorRestrictionsTask;
     955    EventLoopDeferrableTask m_bufferedTimeRangesChangedTask;
     956    EventLoopTaskQueue m_promiseTaskQueue;
     957    EventLoopTaskQueue m_pauseAfterDetachedTaskQueue;
     958    EventLoopTaskQueue m_resourceSelectionTaskQueue;
     959    EventLoopTaskQueue m_visibilityChangeTaskQueue;
     960    EventLoopTaskQueue m_fullscreenTaskQueue;
     961    EventLoopTaskQueue m_playbackTargetIsWirelessQueue;
    962962    RefPtr<TimeRanges> m_playedTimeRanges;
    963963    UniqueRef<MainThreadGenericEventQueue> m_asyncEventQueue;
     
    11631163    bool m_attachingMediaKeys { false };
    11641164    bool m_playbackBlockedWaitingForKey { false };
    1165     GenericTaskQueue<Timer> m_encryptedMediaQueue;
     1165    EventLoopTaskQueue m_encryptedMediaQueue;
    11661166#endif
    11671167
  • trunk/Source/WebCore/html/shadow/MediaControlTextTrackContainerElement.cpp

    r277986 r278392  
    7676MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document& document, HTMLMediaElement& element)
    7777    : HTMLDivElement(divTag, document)
     78    , m_taskQueue(&document)
    7879    , m_mediaElement(makeWeakPtr(&element))
    7980{
  • trunk/Source/WebCore/html/shadow/MediaControlTextTrackContainerElement.h

    r272190 r278392  
    9898    std::unique_ptr<TextTrackRepresentation> m_textTrackRepresentation;
    9999
    100     GenericTaskQueue<Timer> m_taskQueue;
     100    EventLoopTaskQueue m_taskQueue;
    101101    WeakPtr<HTMLMediaElement> m_mediaElement;
    102102    IntRect m_videoDisplaySize;
  • trunk/Source/WebCore/platform/DeferrableTask.h

    r253375 r278392  
    11/*
    2  * Copyright (C) 2018 Apple Inc. All rights reserved.
     2 * Copyright (C) 2018-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2626#pragma once
    2727
     28#include "ContextDestructionObserver.h"
     29#include "EventLoop.h"
    2830#include "GenericTaskQueue.h"
     31#include "ScriptExecutionContext.h"
    2932
    3033namespace WebCore {
    3134
    32 template <typename T>
    33 class DeferrableTask : public CanMakeWeakPtr<DeferrableTask<T>> {
     35class DeferrableTaskBase : public CanMakeWeakPtr<DeferrableTaskBase> {
    3436public:
    35     DeferrableTask()
    36         : m_dispatcher()
    37     {
    38     }
    39 
    40     DeferrableTask(T& t)
    41         : m_dispatcher(&t)
    42     {
    43     }
    44 
    45     typedef WTF::Function<void ()> TaskFunction;
    46 
    47     void scheduleTask(TaskFunction&& task)
    48     {
    49         if (m_isClosed)
    50             return;
    51 
    52         cancelTask();
    53 
    54         m_pendingTask = true;
    55         m_dispatcher.postTask([weakThis = makeWeakPtr(*this), task = WTFMove(task)] {
    56             if (!weakThis)
    57                 return;
    58             ASSERT(weakThis->m_pendingTask);
    59             weakThis->m_pendingTask = false;
    60             task();
    61         });
    62     }
    63 
    6437    void close()
    6538    {
     
    7043    void cancelTask()
    7144    {
    72         CanMakeWeakPtr<DeferrableTask<T>>::weakPtrFactory().revokeAll();
    73         m_pendingTask = false;
     45        weakPtrFactory().revokeAll();
     46        m_isPending = false;
    7447    }
    75     bool hasPendingTask() const { return m_pendingTask; }
     48
     49    bool isPending() const { return m_isPending; }
     50
     51protected:
     52    ~DeferrableTaskBase() = default;
     53    bool isClosed() const { return m_isClosed; }
     54    void setIsPending(bool isPending) { m_isPending = isPending; }
     55
     56private:
     57    bool m_isPending { false };
     58    bool m_isClosed { false };
     59};
     60
     61template <typename T>
     62class DeferrableTask : public DeferrableTaskBase {
     63public:
     64    DeferrableTask()
     65        : m_dispatcher()
     66    { }
     67
     68    DeferrableTask(T& t)
     69        : m_dispatcher(&t)
     70    { }
     71
     72    void scheduleTask(Function<void()>&& task)
     73    {
     74        if (isClosed())
     75            return;
     76
     77        cancelTask();
     78
     79        setIsPending(true);
     80        m_dispatcher.postTask([weakThis = makeWeakPtr(*this), task = WTFMove(task)] {
     81            if (!weakThis)
     82                return;
     83            ASSERT(weakThis->isPending());
     84            weakThis->setIsPending(false);
     85            task();
     86        });
     87    }
    7688
    7789private:
    7890    TaskDispatcher<T> m_dispatcher;
    79     bool m_pendingTask { false };
    80     bool m_isClosed { false };
     91};
     92
     93// Similar to DeferrableTask but based on the HTML event loop.
     94class EventLoopDeferrableTask : public DeferrableTaskBase, private ContextDestructionObserver {
     95public:
     96    EventLoopDeferrableTask(ScriptExecutionContext* context)
     97        : ContextDestructionObserver(context)
     98    { }
     99
     100    // FIXME: Pass TaskSource instead of assuming TaskSource::MediaElement.
     101    void scheduleTask(Function<void()>&& task)
     102    {
     103        if (isClosed() || !scriptExecutionContext())
     104            return;
     105
     106        cancelTask();
     107
     108        setIsPending(true);
     109        scriptExecutionContext()->eventLoop().queueTask(TaskSource::MediaElement, [weakThis = makeWeakPtr(*this), task = WTFMove(task)] {
     110            if (!weakThis)
     111                return;
     112            ASSERT(weakThis->isPending());
     113            weakThis->setIsPending(false);
     114            task();
     115        });
     116    }
    81117};
    82118
  • trunk/Source/WebCore/platform/GenericTaskQueue.h

    r277958 r278392  
    2626#pragma once
    2727
     28#include "ContextDestructionObserver.h"
     29#include "EventLoop.h"
     30#include "ScriptExecutionContext.h"
    2831#include "Timer.h"
    2932#include <wtf/Deque.h>
     
    7679};
    7780
     81class GenericTaskQueueBase : public CanMakeWeakPtr<GenericTaskQueueBase> {
     82public:
     83    bool hasPendingTasks() const { return m_pendingTasks; }
     84    bool isClosed() const { return m_isClosed; }
     85
     86    void close()
     87    {
     88        cancelAllTasks();
     89        m_isClosed = true;
     90    }
     91
     92    void cancelAllTasks()
     93    {
     94        weakPtrFactory().revokeAll();
     95        m_pendingTasks = 0;
     96    }
     97
     98protected:
     99    ~GenericTaskQueueBase() = default;
     100    void incrementPendingTasks() { ++m_pendingTasks; }
     101    void decrementPendingTasks() { ASSERT(m_pendingTasks); --m_pendingTasks; }
     102
     103private:
     104    unsigned m_pendingTasks { 0 };
     105    bool m_isClosed { false };
     106};
     107
    78108template <typename T>
    79 class GenericTaskQueue : public CanMakeWeakPtr<GenericTaskQueue<T>> {
     109class GenericTaskQueue : public GenericTaskQueueBase {
    80110    WTF_MAKE_FAST_ALLOCATED;
    81111public:
     
    94124    explicit GenericTaskQueue(T* t)
    95125        : m_dispatcher(makeUniqueRef<TaskDispatcher<T>>(t))
    96         , m_isClosed(!t)
    97126    {
    98127        ASSERT(isMainThread());
     128        if (!t)
     129            close();
    99130    }
    100131
     
    105136    }
    106137
    107     typedef WTF::Function<void ()> TaskFunction;
    108 
    109     void enqueueTask(TaskFunction&& task)
     138    void enqueueTask(Function<void()>&& task)
    110139    {
    111         if (m_isClosed)
     140        if (isClosed())
    112141            return;
    113142
    114         ++m_pendingTasks;
     143        incrementPendingTasks();
    115144        m_dispatcher->postTask([weakThis = makeWeakPtr(*this), task = WTFMove(task)] {
    116145            if (!weakThis)
    117146                return;
    118             ASSERT(weakThis->m_pendingTasks);
    119             --weakThis->m_pendingTasks;
     147            weakThis->decrementPendingTasks();
    120148            task();
    121149        });
    122150    }
    123151
    124     void close()
    125     {
    126         cancelAllTasks();
    127         m_isClosed = true;
    128     }
    129 
    130     void cancelAllTasks()
    131     {
    132         CanMakeWeakPtr<GenericTaskQueue<T>>::weakPtrFactory().revokeAll();
    133         m_pendingTasks = 0;
    134     }
    135 
    136     bool hasPendingTasks() const { return m_pendingTasks; }
    137     bool isClosed() const { return m_isClosed; }
    138 
    139152private:
    140153    UniqueRef<TaskDispatcher<T>> m_dispatcher;
    141     unsigned m_pendingTasks { 0 };
    142     bool m_isClosed { false };
     154};
     155
     156// Similar to GenericTaskQueue but based on the HTML event loop.
     157class EventLoopTaskQueue : public GenericTaskQueueBase, private ContextDestructionObserver {
     158public:
     159    EventLoopTaskQueue(ScriptExecutionContext* context)
     160        : ContextDestructionObserver(context)
     161    { }
     162
     163    // FIXME: Pass a TaskSource instead of assuming TaskSource::MediaElement.
     164    void enqueueTask(Function<void()>&& task)
     165    {
     166        if (isClosed() || !scriptExecutionContext())
     167            return;
     168
     169        incrementPendingTasks();
     170        scriptExecutionContext()->eventLoop().queueTask(TaskSource::MediaElement, [weakThis = makeWeakPtr(*this), task = WTFMove(task)] {
     171            if (!weakThis)
     172                return;
     173            weakThis->decrementPendingTasks();
     174            task();
     175        });
     176    }
    143177};
    144178
  • trunk/Source/WebCore/platform/RemoteCommandListener.cpp

    r273967 r278392  
    7272void RemoteCommandListener::scheduleSupportedCommandsUpdate()
    7373{
    74     if (!m_updateCommandsTask.hasPendingTask()) {
     74    if (!m_updateCommandsTask.isPending()) {
    7575        m_updateCommandsTask.scheduleTask([this] ()  {
    7676            updateSupportedCommands();
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm

    r264006 r278392  
    184184    }
    185185
    186     ASSERT(!m_mappingCallback && !m_mappingCallbackTask.hasPendingTask());
     186    ASSERT(!m_mappingCallback && !m_mappingCallbackTask.isPending());
    187187
    188188    // An existing callback means this buffer is in the mapped state.
  • trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUQueueMetal.mm

    r264006 r278392  
    9797    }
    9898
    99     if (m_presentTask.hasPendingTask() || !m_device || !m_device->swapChain())
     99    if (m_presentTask.isPending() || !m_device || !m_device->swapChain())
    100100        return;
    101101
Note: See TracChangeset for help on using the changeset viewer.