IdleCallbackController.cpp [plain text]
#include "config.h"
#include "IdleCallbackController.h"
#include "Document.h"
#include "IdleDeadline.h"
#include "WindowEventLoop.h"
namespace WebCore {
IdleCallbackController::IdleCallbackController(Document& document)
: m_document(makeWeakPtr(document))
{
}
int IdleCallbackController::queueIdleCallback(Ref<IdleRequestCallback>&& callback, Seconds)
{
bool startIdlePeriod = m_idleRequestCallbacks.isEmpty() && m_runnableIdleCallbacks.isEmpty();
++m_idleCallbackIdentifier;
auto handle = m_idleCallbackIdentifier;
m_idleRequestCallbacks.append({ handle, WTFMove(callback) });
if (startIdlePeriod)
queueTaskToStartIdlePeriod();
return handle;
}
void IdleCallbackController::removeIdleCallback(int signedIdentifier)
{
if (signedIdentifier <= 0)
return;
unsigned identifier = signedIdentifier;
m_idleRequestCallbacks.removeAllMatching([identifier](auto& request) {
return request.identifier == identifier;
});
m_runnableIdleCallbacks.removeAllMatching([identifier](auto& request) {
return request.identifier == identifier;
});
}
void IdleCallbackController::queueTaskToStartIdlePeriod()
{
m_document->eventLoop().queueTask(TaskSource::IdleTask, [protectedDocument = makeRef(*m_document), this] {
RELEASE_ASSERT(protectedDocument->idleCallbackController() == this);
startIdlePeriod();
});
}
static const auto deadlineCapToEnsureResponsiveness = 50_ms;
void IdleCallbackController::startIdlePeriod()
{
auto now = MonotonicTime::now();
if (m_lastDeadline > now)
return;
auto deadline = now + deadlineCapToEnsureResponsiveness;
for (auto& request : m_idleRequestCallbacks)
m_runnableIdleCallbacks.append({ request.identifier, WTFMove(request.callback) });
m_idleRequestCallbacks.clear();
ASSERT(!m_runnableIdleCallbacks.isEmpty());
queueTaskToInvokeIdleCallbacks(deadline);
m_lastDeadline = deadline;
}
void IdleCallbackController::queueTaskToInvokeIdleCallbacks(MonotonicTime deadline)
{
m_document->eventLoop().queueTask(TaskSource::IdleTask, [protectedDocument = makeRef(*m_document), deadline, this] {
RELEASE_ASSERT(protectedDocument->idleCallbackController() == this);
invokeIdleCallbacks(deadline);
});
}
void IdleCallbackController::invokeIdleCallbacks(MonotonicTime deadline)
{
if (!m_document)
return;
auto now = MonotonicTime::now();
if (now < deadline) {
if (m_runnableIdleCallbacks.isEmpty())
return;
auto request = m_runnableIdleCallbacks.takeFirst();
auto idleDeadline = IdleDeadline::create(deadline);
request.callback->handleEvent(idleDeadline.get());
if (!m_runnableIdleCallbacks.isEmpty())
queueTaskToInvokeIdleCallbacks(deadline);
return;
}
if (!m_idleRequestCallbacks.isEmpty() || !m_runnableIdleCallbacks.isEmpty())
queueTaskToStartIdlePeriod();
}
}