XMLHttpRequestProgressEventThrottle.cpp [plain text]
#include "config.h"
#include "XMLHttpRequestProgressEventThrottle.h"
#include "EventNames.h"
#include "EventTarget.h"
#include "XMLHttpRequest.h"
#include "XMLHttpRequestProgressEvent.h"
namespace WebCore {
const Seconds XMLHttpRequestProgressEventThrottle::minimumProgressEventDispatchingInterval { 50_ms };
XMLHttpRequestProgressEventThrottle::XMLHttpRequestProgressEventThrottle(XMLHttpRequest& target)
: m_target(target)
, m_dispatchThrottledProgressEventTimer(target.scriptExecutionContext(), *this, &XMLHttpRequestProgressEventThrottle::dispatchThrottledProgressEventTimerFired)
{
m_dispatchThrottledProgressEventTimer.suspendIfNeeded();
}
XMLHttpRequestProgressEventThrottle::~XMLHttpRequestProgressEventThrottle() = default;
void XMLHttpRequestProgressEventThrottle::dispatchThrottledProgressEvent(bool lengthComputable, unsigned long long loaded, unsigned long long total)
{
m_lengthComputable = lengthComputable;
m_loaded = loaded;
m_total = total;
if (!m_target.hasEventListeners(eventNames().progressEvent))
return;
if (!m_shouldDeferEventsDueToSuspension && !m_dispatchThrottledProgressEventTimer.isActive()) {
ASSERT(!m_hasPendingThrottledProgressEvent);
dispatchEventWhenPossible(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, lengthComputable, loaded, total));
m_dispatchThrottledProgressEventTimer.startRepeating(minimumProgressEventDispatchingInterval);
m_hasPendingThrottledProgressEvent = false;
return;
}
m_hasPendingThrottledProgressEvent = true;
}
void XMLHttpRequestProgressEventThrottle::dispatchReadyStateChangeEvent(Event& event, ProgressEventAction progressEventAction)
{
if (progressEventAction == FlushProgressEvent)
flushProgressEvent();
dispatchEventWhenPossible(event);
}
void XMLHttpRequestProgressEventThrottle::dispatchEventWhenPossible(Event& event)
{
if (m_shouldDeferEventsDueToSuspension)
m_target.queueTaskToDispatchEvent(m_target, TaskSource::Networking, makeRef(event));
else
m_target.dispatchEvent(event);
}
void XMLHttpRequestProgressEventThrottle::dispatchProgressEvent(const AtomString& type)
{
ASSERT(type == eventNames().loadstartEvent || type == eventNames().progressEvent || type == eventNames().loadEvent || type == eventNames().loadendEvent || type == eventNames().abortEvent || type == eventNames().errorEvent || type == eventNames().timeoutEvent);
if (type == eventNames().loadstartEvent) {
m_lengthComputable = false;
m_loaded = 0;
m_total = 0;
}
if (m_target.hasEventListeners(type))
dispatchEventWhenPossible(XMLHttpRequestProgressEvent::create(type, m_lengthComputable, m_loaded, m_total));
}
void XMLHttpRequestProgressEventThrottle::flushProgressEvent()
{
if (!m_hasPendingThrottledProgressEvent)
return;
m_hasPendingThrottledProgressEvent = false;
m_dispatchThrottledProgressEventTimer.cancel();
dispatchEventWhenPossible(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, m_lengthComputable, m_loaded, m_total));
}
void XMLHttpRequestProgressEventThrottle::dispatchThrottledProgressEventTimerFired()
{
ASSERT(m_dispatchThrottledProgressEventTimer.isActive());
if (!m_hasPendingThrottledProgressEvent) {
m_dispatchThrottledProgressEventTimer.cancel();
return;
}
dispatchEventWhenPossible(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, m_lengthComputable, m_loaded, m_total));
m_hasPendingThrottledProgressEvent = false;
}
void XMLHttpRequestProgressEventThrottle::suspend()
{
m_shouldDeferEventsDueToSuspension = true;
if (m_hasPendingThrottledProgressEvent) {
m_target.queueTaskKeepingObjectAlive(m_target, TaskSource::Networking, [this] {
flushProgressEvent();
});
}
}
void XMLHttpRequestProgressEventThrottle::resume()
{
m_target.queueTaskKeepingObjectAlive(m_target, TaskSource::Networking, [this] {
m_shouldDeferEventsDueToSuspension = false;
});
}
}