WindowEventLoop.cpp [plain text]
#include "config.h"
#include "WindowEventLoop.h"
#include "CommonVM.h"
#include "CustomElementReactionQueue.h"
#include "Document.h"
#include "HTMLSlotElement.h"
#include "Microtasks.h"
#include "MutationObserver.h"
#include "SecurityOrigin.h"
#include "ThreadGlobalData.h"
#include <wtf/RunLoop.h>
namespace WebCore {
static HashMap<String, WindowEventLoop*>& windowEventLoopMap()
{
RELEASE_ASSERT(isMainThread());
static NeverDestroyed<HashMap<String, WindowEventLoop*>> map;
return map.get();
}
static String agentClusterKeyOrNullIfUnique(const SecurityOrigin& origin)
{
auto computeKey = [&] {
if (origin.isUnique())
return origin.toString();
RegistrableDomain registrableDomain { origin.data() };
if (registrableDomain.isEmpty())
return origin.toString();
return makeString(origin.protocol(), "://", registrableDomain.string());
};
auto key = computeKey();
if (key.isEmpty() || key == "null"_s)
return { };
return key;
}
Ref<WindowEventLoop> WindowEventLoop::eventLoopForSecurityOrigin(const SecurityOrigin& origin)
{
auto key = agentClusterKeyOrNullIfUnique(origin);
if (key.isNull())
return create({ });
auto addResult = windowEventLoopMap().add(key, nullptr);
if (UNLIKELY(addResult.isNewEntry)) {
auto newEventLoop = create(key);
addResult.iterator->value = newEventLoop.ptr();
return newEventLoop;
}
return *addResult.iterator->value;
}
inline Ref<WindowEventLoop> WindowEventLoop::create(const String& agentClusterKey)
{
return adoptRef(*new WindowEventLoop(agentClusterKey));
}
inline WindowEventLoop::WindowEventLoop(const String& agentClusterKey)
: m_agentClusterKey(agentClusterKey)
, m_timer(*this, &WindowEventLoop::didReachTimeToRun)
, m_perpetualTaskGroupForSimilarOriginWindowAgents(*this)
{
}
WindowEventLoop::~WindowEventLoop()
{
if (m_agentClusterKey.isNull())
return;
auto didRemove = windowEventLoopMap().remove(m_agentClusterKey);
RELEASE_ASSERT(didRemove);
}
void WindowEventLoop::scheduleToRun()
{
m_timer.startOneShot(0_s);
}
bool WindowEventLoop::isContextThread() const
{
return isMainThread();
}
MicrotaskQueue& WindowEventLoop::microtaskQueue()
{
if (!m_microtaskQueue)
m_microtaskQueue = makeUnique<MicrotaskQueue>(commonVM());
return *m_microtaskQueue;
}
void WindowEventLoop::didReachTimeToRun()
{
auto protectedThis = makeRef(*this); run();
}
void WindowEventLoop::queueMutationObserverCompoundMicrotask()
{
if (m_mutationObserverCompoundMicrotaskQueuedFlag)
return;
m_mutationObserverCompoundMicrotaskQueuedFlag = true;
m_perpetualTaskGroupForSimilarOriginWindowAgents.queueMicrotask([this] {
auto protectedThis = makeRef(*this);
m_mutationObserverCompoundMicrotaskQueuedFlag = false;
if (m_deliveringMutationRecords)
return;
m_deliveringMutationRecords = true;
MutationObserver::notifyMutationObservers(*this);
m_deliveringMutationRecords = false;
});
}
CustomElementQueue& WindowEventLoop::backupElementQueue()
{
if (!m_processingBackupElementQueue) {
m_processingBackupElementQueue = true;
m_perpetualTaskGroupForSimilarOriginWindowAgents.queueMicrotask([this] {
auto protectedThis = makeRef(*this);
m_processingBackupElementQueue = false;
ASSERT(m_customElementQueue);
CustomElementReactionQueue::processBackupQueue(*m_customElementQueue);
});
}
if (!m_customElementQueue)
m_customElementQueue = makeUnique<CustomElementQueue>();
return *m_customElementQueue;
}
void WindowEventLoop::breakToAllowRenderingUpdate()
{
#if PLATFORM(MAC)
threadGlobalData().threadTimers().breakFireLoopForRenderingUpdate();
RunLoop::main().suspendFunctionDispatchForCurrentCycle();
#endif
}
}