#include "config.h"
#if ENABLE(WORKERS)
#include "Worker.h"
#include "CachedScript.h"
#include "DOMWindow.h"
#include "DocLoader.h"
#include "Document.h"
#include "EventException.h"
#include "EventListener.h"
#include "EventNames.h"
#include "ExceptionCode.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "MessageEvent.h"
#include "SecurityOrigin.h"
#include "TextEncoding.h"
#include "WorkerContextProxy.h"
#include "WorkerThread.h"
#include <wtf/MainThread.h>
namespace WebCore {
Worker::Worker(const String& url, ScriptExecutionContext* context, ExceptionCode& ec)
: ActiveDOMObject(context, this)
, m_contextProxy(WorkerContextProxy::create(this))
{
m_scriptURL = context->completeURL(url);
if (url.isEmpty() || !m_scriptURL.isValid()) {
ec = SYNTAX_ERR;
return;
}
if (!context->securityOrigin()->canAccess(SecurityOrigin::create(m_scriptURL).get())) {
ec = SECURITY_ERR;
return;
}
ASSERT(scriptExecutionContext()->isDocument());
Document* document = static_cast<Document*>(scriptExecutionContext());
m_cachedScript = document->docLoader()->requestScript(m_scriptURL, "UTF-8");
if (!m_cachedScript) {
dispatchErrorEvent();
return;
}
setPendingActivity(this); m_cachedScript->addClient(this);
}
Worker::~Worker()
{
ASSERT(isMainThread());
ASSERT(scriptExecutionContext()); m_contextProxy->workerObjectDestroyed();
}
void Worker::postMessage(const String& message)
{
m_contextProxy->postMessageToWorkerContext(message);
}
void Worker::terminate()
{
m_contextProxy->terminateWorkerContext();
}
bool Worker::canSuspend() const
{
return false;
}
void Worker::stop()
{
terminate();
}
bool Worker::hasPendingActivity() const
{
return m_contextProxy->hasPendingActivity() || ActiveDOMObject::hasPendingActivity();
}
void Worker::notifyFinished(CachedResource* unusedResource)
{
ASSERT_UNUSED(unusedResource, unusedResource == m_cachedScript);
if (m_cachedScript->errorOccurred())
dispatchErrorEvent();
else
m_contextProxy->startWorkerContext(m_scriptURL, scriptExecutionContext()->userAgent(m_scriptURL), m_cachedScript->script());
m_cachedScript->removeClient(this);
m_cachedScript = 0;
unsetPendingActivity(this);
}
void Worker::dispatchErrorEvent()
{
RefPtr<Event> evt = Event::create(eventNames().errorEvent, false, true);
if (m_onErrorListener) {
evt->setTarget(this);
evt->setCurrentTarget(this);
m_onErrorListener->handleEvent(evt.get(), true);
}
ExceptionCode ec = 0;
dispatchEvent(evt.release(), ec);
ASSERT(!ec);
}
void Worker::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool)
{
EventListenersMap::iterator iter = m_eventListeners.find(eventType);
if (iter == m_eventListeners.end()) {
ListenerVector listeners;
listeners.append(eventListener);
m_eventListeners.add(eventType, listeners);
} else {
ListenerVector& listeners = iter->second;
for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) {
if (*listenerIter == eventListener)
return;
}
listeners.append(eventListener);
m_eventListeners.add(eventType, listeners);
}
}
void Worker::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool)
{
EventListenersMap::iterator iter = m_eventListeners.find(eventType);
if (iter == m_eventListeners.end())
return;
ListenerVector& listeners = iter->second;
for (ListenerVector::const_iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) {
if (*listenerIter == eventListener) {
listeners.remove(listenerIter - listeners.begin());
return;
}
}
}
bool Worker::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec)
{
if (!event || event->type().isEmpty()) {
ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
return true;
}
ListenerVector listenersCopy = m_eventListeners.get(event->type());
for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) {
event->setTarget(this);
event->setCurrentTarget(this);
listenerIter->get()->handleEvent(event.get(), false);
}
return !event->defaultPrevented();
}
void Worker::dispatchMessage(const String& message)
{
RefPtr<Event> evt = MessageEvent::create(message, "", "", 0, 0);
if (m_onMessageListener.get()) {
evt->setTarget(this);
evt->setCurrentTarget(this);
m_onMessageListener->handleEvent(evt.get(), false);
}
ExceptionCode ec = 0;
dispatchEvent(evt.release(), ec);
ASSERT(!ec);
}
}
#endif // ENABLE(WORKERS)