#include "config.h"
#include "ScriptRunner.h"
#include "Element.h"
#include "PendingScript.h"
#include "ScriptElement.h"
namespace WebCore {
ScriptRunner::ScriptRunner(Document& document)
: m_document(document)
, m_timer(*this, &ScriptRunner::timerFired)
{
}
ScriptRunner::~ScriptRunner()
{
for (auto& pendingScript : m_scriptsToExecuteSoon) {
UNUSED_PARAM(pendingScript);
m_document.decrementLoadEventDelayCount();
}
for (auto& pendingScript : m_scriptsToExecuteInOrder) {
if (pendingScript->watchingForLoad())
pendingScript->clearClient();
m_document.decrementLoadEventDelayCount();
}
for (auto& pendingScript : m_pendingAsyncScripts) {
if (pendingScript->watchingForLoad())
const_cast<PendingScript&>(pendingScript.get()).clearClient();
m_document.decrementLoadEventDelayCount();
}
}
void ScriptRunner::queueScriptForExecution(ScriptElement* scriptElement, LoadableScript& loadableScript, ExecutionType executionType)
{
ASSERT(scriptElement);
Element& element = scriptElement->element();
ASSERT(element.inDocument());
m_document.incrementLoadEventDelayCount();
Ref<PendingScript> pendingScript = PendingScript::create(element, loadableScript);
switch (executionType) {
case ASYNC_EXECUTION:
m_pendingAsyncScripts.add(pendingScript.copyRef());
break;
case IN_ORDER_EXECUTION:
m_scriptsToExecuteInOrder.append(pendingScript.copyRef());
break;
}
pendingScript->setClient(this);
}
void ScriptRunner::suspend()
{
m_timer.stop();
}
void ScriptRunner::resume()
{
if (hasPendingScripts())
m_timer.startOneShot(0);
}
void ScriptRunner::notifyFinished(PendingScript& pendingScript)
{
auto* scriptElement = toScriptElementIfPossible(&pendingScript.element());
ASSERT(scriptElement);
if (scriptElement->willExecuteInOrder())
ASSERT(!m_scriptsToExecuteInOrder.isEmpty());
else {
ASSERT(m_pendingAsyncScripts.contains(pendingScript));
m_scriptsToExecuteSoon.append(m_pendingAsyncScripts.take(pendingScript)->ptr());
}
pendingScript.clearClient();
m_timer.startOneShot(0);
}
void ScriptRunner::timerFired()
{
Ref<Document> protect(m_document);
Vector<RefPtr<PendingScript>> scripts;
scripts.swap(m_scriptsToExecuteSoon);
size_t numInOrderScriptsToExecute = 0;
for (; numInOrderScriptsToExecute < m_scriptsToExecuteInOrder.size() && m_scriptsToExecuteInOrder[numInOrderScriptsToExecute]->isLoaded(); ++numInOrderScriptsToExecute)
scripts.append(m_scriptsToExecuteInOrder[numInOrderScriptsToExecute].ptr());
if (numInOrderScriptsToExecute)
m_scriptsToExecuteInOrder.remove(0, numInOrderScriptsToExecute);
for (auto& currentScript : scripts) {
auto script = WTFMove(currentScript);
ASSERT(script);
if (!script)
continue;
auto* scriptElement = toScriptElementIfPossible(&script->element());
ASSERT(scriptElement);
ASSERT(script->needsLoading());
scriptElement->executePendingScript(*script);
m_document.decrementLoadEventDelayCount();
}
}
}