summaryrefslogtreecommitdiffstats
path: root/WebCore/workers
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/workers')
-rw-r--r--WebCore/workers/AbstractWorker.cpp94
-rw-r--r--WebCore/workers/AbstractWorker.h22
-rw-r--r--WebCore/workers/AbstractWorker.idl2
-rw-r--r--WebCore/workers/DedicatedWorkerContext.cpp47
-rw-r--r--WebCore/workers/DedicatedWorkerContext.h18
-rw-r--r--WebCore/workers/DedicatedWorkerContext.idl7
-rw-r--r--WebCore/workers/DedicatedWorkerThread.cpp2
-rw-r--r--WebCore/workers/DefaultSharedWorkerRepository.cpp239
-rw-r--r--WebCore/workers/DefaultSharedWorkerRepository.h28
-rw-r--r--WebCore/workers/SharedWorkerContext.cpp38
-rw-r--r--WebCore/workers/SharedWorkerContext.h14
-rw-r--r--WebCore/workers/SharedWorkerContext.idl1
-rw-r--r--WebCore/workers/SharedWorkerRepository.h11
-rw-r--r--WebCore/workers/SharedWorkerThread.cpp10
-rw-r--r--WebCore/workers/SharedWorkerThread.h4
-rw-r--r--WebCore/workers/Worker.cpp38
-rw-r--r--WebCore/workers/Worker.h19
-rw-r--r--WebCore/workers/Worker.idl10
-rw-r--r--WebCore/workers/WorkerContext.cpp104
-rw-r--r--WebCore/workers/WorkerContext.h34
-rw-r--r--WebCore/workers/WorkerContext.idl8
-rw-r--r--WebCore/workers/WorkerContextProxy.h4
-rw-r--r--WebCore/workers/WorkerMessagingProxy.cpp95
-rw-r--r--WebCore/workers/WorkerMessagingProxy.h6
-rw-r--r--WebCore/workers/WorkerObjectProxy.h19
-rw-r--r--WebCore/workers/WorkerReportingProxy.h61
-rw-r--r--WebCore/workers/WorkerRunLoop.cpp8
-rw-r--r--WebCore/workers/WorkerScriptLoader.cpp17
-rw-r--r--WebCore/workers/WorkerScriptLoader.h4
-rw-r--r--WebCore/workers/WorkerThread.cpp27
-rw-r--r--WebCore/workers/WorkerThread.h21
31 files changed, 593 insertions, 419 deletions
diff --git a/WebCore/workers/AbstractWorker.cpp b/WebCore/workers/AbstractWorker.cpp
index 2371e9d..6ba8922 100644
--- a/WebCore/workers/AbstractWorker.cpp
+++ b/WebCore/workers/AbstractWorker.cpp
@@ -52,90 +52,6 @@ AbstractWorker::~AbstractWorker()
{
}
-void AbstractWorker::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 AbstractWorker::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 AbstractWorker::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 AbstractWorker::dispatchLoadErrorEvent()
-{
- 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);
-}
-
-bool AbstractWorker::dispatchScriptErrorEvent(const String& message, const String& sourceURL, int lineNumber)
-{
- bool handled = false;
- RefPtr<ErrorEvent> event = ErrorEvent::create(message, sourceURL, static_cast<unsigned>(lineNumber));
- if (m_onErrorListener) {
- event->setTarget(this);
- event->setCurrentTarget(this);
- m_onErrorListener->handleEvent(event.get(), true);
- if (event->defaultPrevented())
- handled = true;
- }
-
- ExceptionCode ec = 0;
- dispatchEvent(event.release(), ec);
- ASSERT(!ec);
-
- return handled;
-}
-
KURL AbstractWorker::resolveURL(const String& url, ExceptionCode& ec)
{
if (url.isEmpty()) {
@@ -157,6 +73,16 @@ KURL AbstractWorker::resolveURL(const String& url, ExceptionCode& ec)
return scriptURL;
}
+EventTargetData* AbstractWorker::eventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+EventTargetData* AbstractWorker::ensureEventTargetData()
+{
+ return &m_eventTargetData;
+}
+
} // namespace WebCore
#endif // ENABLE(WORKERS)
diff --git a/WebCore/workers/AbstractWorker.h b/WebCore/workers/AbstractWorker.h
index a882542..2209856 100644
--- a/WebCore/workers/AbstractWorker.h
+++ b/WebCore/workers/AbstractWorker.h
@@ -36,6 +36,7 @@
#include "ActiveDOMObject.h"
#include "AtomicStringHash.h"
#include "EventListener.h"
+#include "EventNames.h"
#include "EventTarget.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -51,19 +52,7 @@ namespace WebCore {
// EventTarget APIs
virtual ScriptExecutionContext* scriptExecutionContext() const { return ActiveDOMObject::scriptExecutionContext(); }
- virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
- virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
- virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&);
-
- // Utility routines to generate appropriate error events for loading and script exceptions.
- void dispatchLoadErrorEvent();
- bool dispatchScriptErrorEvent(const String& errorMessage, const String& sourceURL, int);
-
- void setOnerror(PassRefPtr<EventListener> eventListener) { m_onErrorListener = eventListener; }
- EventListener* onerror() const { return m_onErrorListener.get(); }
- typedef Vector<RefPtr<EventListener> > ListenerVector;
- typedef HashMap<AtomicString, ListenerVector> EventListenersMap;
- EventListenersMap& eventListeners() { return m_eventListeners; }
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
using RefCounted<AbstractWorker>::ref;
using RefCounted<AbstractWorker>::deref;
@@ -78,9 +67,10 @@ namespace WebCore {
private:
virtual void refEventTarget() { ref(); }
virtual void derefEventTarget() { deref(); }
-
- RefPtr<EventListener> m_onErrorListener;
- EventListenersMap m_eventListeners;
+ virtual EventTargetData* eventTargetData();
+ virtual EventTargetData* ensureEventTargetData();
+
+ EventTargetData m_eventTargetData;
};
} // namespace WebCore
diff --git a/WebCore/workers/AbstractWorker.idl b/WebCore/workers/AbstractWorker.idl
index ae7ebc6..00b8fbb 100644
--- a/WebCore/workers/AbstractWorker.idl
+++ b/WebCore/workers/AbstractWorker.idl
@@ -32,8 +32,8 @@ module threads {
interface [
Conditional=WORKERS,
- CustomMarkFunction,
CustomToJS,
+ EventTarget,
GenerateConstructor
] AbstractWorker {
diff --git a/WebCore/workers/DedicatedWorkerContext.cpp b/WebCore/workers/DedicatedWorkerContext.cpp
index ae5c547..82dc4b3 100644
--- a/WebCore/workers/DedicatedWorkerContext.cpp
+++ b/WebCore/workers/DedicatedWorkerContext.cpp
@@ -46,54 +46,29 @@ DedicatedWorkerContext::DedicatedWorkerContext(const KURL& url, const String& us
{
}
-DedicatedWorkerContext::~DedicatedWorkerContext()
+// FIXME: remove this when we update the ObjC bindings (bug #28774).
+void DedicatedWorkerContext::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, ExceptionCode& ec)
{
- ASSERT(currentThread() == thread()->threadID());
- // Notify parent worker we are going away. This can free the WorkerThread object, so do not access it after this.
- thread()->workerObjectProxy().workerContextDestroyed();
+ MessagePortArray ports;
+ if (port)
+ ports.append(port);
+ postMessage(message, &ports, ec);
}
-void DedicatedWorkerContext::forwardException(const String& errorMessage, int lineNumber, const String& sourceURL)
+void DedicatedWorkerContext::postMessage(PassRefPtr<SerializedScriptValue> message, ExceptionCode& ec)
{
- thread()->workerObjectProxy().postExceptionToWorkerObject(errorMessage, lineNumber, sourceURL);
+ postMessage(message, static_cast<MessagePortArray*>(0), ec);
}
-void DedicatedWorkerContext::addMessage(MessageDestination destination, MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL)
-{
- thread()->workerObjectProxy().postConsoleMessageToWorkerObject(destination, source, type, level, message, lineNumber, sourceURL);
-}
-
-void DedicatedWorkerContext::postMessage(const String& message, ExceptionCode& ec)
-{
- postMessage(message, 0, ec);
-}
-
-void DedicatedWorkerContext::postMessage(const String& message, MessagePort* port, ExceptionCode& ec)
+void DedicatedWorkerContext::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, ExceptionCode& ec)
{
if (isClosing())
return;
// Disentangle the port in preparation for sending it to the remote context.
- OwnPtr<MessagePortChannel> channel = port ? port->disentangle(ec) : 0;
+ OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec);
if (ec)
return;
- thread()->workerObjectProxy().postMessageToWorkerObject(message, channel.release());
-}
-
-void DedicatedWorkerContext::dispatchMessage(const String& message, PassRefPtr<MessagePort> port)
-{
- // Since close() stops the thread event loop, this should not ever get called while closing.
- ASSERT(!isClosing());
- RefPtr<Event> evt = MessageEvent::create(message, "", "", 0, port);
-
- 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);
+ thread()->workerObjectProxy().postMessageToWorkerObject(message, channels.release());
}
void DedicatedWorkerContext::importScripts(const Vector<String>& urls, const String& callerURL, int callerLine, ExceptionCode& ec)
diff --git a/WebCore/workers/DedicatedWorkerContext.h b/WebCore/workers/DedicatedWorkerContext.h
index e974cef..74a39d9 100644
--- a/WebCore/workers/DedicatedWorkerContext.h
+++ b/WebCore/workers/DedicatedWorkerContext.h
@@ -33,6 +33,7 @@
#if ENABLE(WORKERS)
+#include "MessagePort.h"
#include "WorkerContext.h"
namespace WebCore {
@@ -46,31 +47,24 @@ namespace WebCore {
{
return adoptRef(new DedicatedWorkerContext(url, userAgent, thread));
}
- virtual ~DedicatedWorkerContext();
virtual bool isDedicatedWorkerContext() const { return true; }
// Overridden to allow us to check our pending activity after executing imported script.
virtual void importScripts(const Vector<String>& urls, const String& callerURL, int callerLine, ExceptionCode&);
- // ScriptExecutionContext
- virtual void addMessage(MessageDestination, MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL);
-
- virtual void forwardException(const String& errorMessage, int lineNumber, const String& sourceURL);
-
// EventTarget
virtual DedicatedWorkerContext* toDedicatedWorkerContext() { return this; }
- void postMessage(const String&, ExceptionCode&);
- void postMessage(const String&, MessagePort*, ExceptionCode&);
- void setOnmessage(PassRefPtr<EventListener> eventListener) { m_onmessageListener = eventListener; }
- EventListener* onmessage() const { return m_onmessageListener.get(); }
+ void postMessage(PassRefPtr<SerializedScriptValue>, ExceptionCode&);
+ void postMessage(PassRefPtr<SerializedScriptValue>, const MessagePortArray*, ExceptionCode&);
+ // FIXME: remove this when we update the ObjC bindings (bug #28774).
+ void postMessage(PassRefPtr<SerializedScriptValue>, MessagePort*, ExceptionCode&);
- void dispatchMessage(const String&, PassRefPtr<MessagePort>);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(message);
DedicatedWorkerThread* thread();
private:
DedicatedWorkerContext(const KURL&, const String&, DedicatedWorkerThread*);
- RefPtr<EventListener> m_onmessageListener;
};
} // namespace WebCore
diff --git a/WebCore/workers/DedicatedWorkerContext.idl b/WebCore/workers/DedicatedWorkerContext.idl
index ebbee33..f421b9a 100644
--- a/WebCore/workers/DedicatedWorkerContext.idl
+++ b/WebCore/workers/DedicatedWorkerContext.idl
@@ -32,15 +32,20 @@ module threads {
interface [
Conditional=WORKERS,
- CustomMarkFunction,
ExtendsDOMGlobalObject,
IsWorkerContext,
GenerateNativeConverter,
NoStaticTables
] DedicatedWorkerContext : WorkerContext {
+#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
+ [Custom] void postMessage(in any message, in [Optional] Array messagePorts)
+ raises(DOMException);
+#else
+ // There's no good way to expose an array via the ObjC bindings, so for now just allow passing in a single port.
void postMessage(in DOMString message, in [Optional] MessagePort messagePort)
raises(DOMException);
+#endif
attribute EventListener onmessage;
};
diff --git a/WebCore/workers/DedicatedWorkerThread.cpp b/WebCore/workers/DedicatedWorkerThread.cpp
index 0905843..d4789a1 100644
--- a/WebCore/workers/DedicatedWorkerThread.cpp
+++ b/WebCore/workers/DedicatedWorkerThread.cpp
@@ -45,7 +45,7 @@ PassRefPtr<DedicatedWorkerThread> DedicatedWorkerThread::create(const KURL& scri
}
DedicatedWorkerThread::DedicatedWorkerThread(const KURL& url, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerObjectProxy& workerObjectProxy)
- : WorkerThread(url, userAgent, sourceCode, workerLoaderProxy)
+ : WorkerThread(url, userAgent, sourceCode, workerLoaderProxy, workerObjectProxy)
, m_workerObjectProxy(workerObjectProxy)
{
}
diff --git a/WebCore/workers/DefaultSharedWorkerRepository.cpp b/WebCore/workers/DefaultSharedWorkerRepository.cpp
index 1c1ed4c..8b1a480 100644
--- a/WebCore/workers/DefaultSharedWorkerRepository.cpp
+++ b/WebCore/workers/DefaultSharedWorkerRepository.cpp
@@ -35,6 +35,9 @@
#include "DefaultSharedWorkerRepository.h"
#include "ActiveDOMObject.h"
+#include "Document.h"
+#include "GenericWorkerTask.h"
+#include "MessageEvent.h"
#include "MessagePort.h"
#include "NotImplemented.h"
#include "PlatformString.h"
@@ -42,52 +45,178 @@
#include "SecurityOriginHash.h"
#include "SharedWorker.h"
#include "SharedWorkerContext.h"
+#include "SharedWorkerRepository.h"
#include "SharedWorkerThread.h"
#include "WorkerLoaderProxy.h"
+#include "WorkerReportingProxy.h"
#include "WorkerScriptLoader.h"
#include "WorkerScriptLoaderClient.h"
-
+#include <wtf/HashSet.h>
#include <wtf/Threading.h>
namespace WebCore {
-class SharedWorkerProxy : public ThreadSafeShared<SharedWorkerProxy>, public WorkerLoaderProxy {
+class SharedWorkerProxy : public ThreadSafeShared<SharedWorkerProxy>, public WorkerLoaderProxy, public WorkerReportingProxy {
public:
- static PassRefPtr<SharedWorkerProxy> create(const String& name, const KURL& url) { return adoptRef(new SharedWorkerProxy(name, url)); }
+ static PassRefPtr<SharedWorkerProxy> create(const String& name, const KURL& url, PassRefPtr<SecurityOrigin> origin) { return adoptRef(new SharedWorkerProxy(name, url, origin)); }
void setThread(PassRefPtr<SharedWorkerThread> thread) { m_thread = thread; }
SharedWorkerThread* thread() { return m_thread.get(); }
- bool closing() const { return m_closing; }
- KURL url() const { return m_url.copy(); }
- String name() const { return m_name.copy(); }
+ bool isClosing() const { return m_closing; }
+ KURL url() const
+ {
+ // Don't use m_url.copy() because it isn't a threadsafe method.
+ return KURL(ParsedURLString, m_url.string().threadsafeCopy());
+ }
+
+ String name() const { return m_name.threadsafeCopy(); }
+ bool matches(const String& name, PassRefPtr<SecurityOrigin> origin, const KURL& urlToMatch) const;
// WorkerLoaderProxy
- // FIXME: Implement WorkerLoaderProxy APIs by proxying to an active document.
- virtual void postTaskToLoader(PassRefPtr<ScriptExecutionContext::Task>) { notImplemented(); }
- virtual void postTaskForModeToWorkerContext(PassRefPtr<ScriptExecutionContext::Task>, const String&) { notImplemented(); }
+ virtual void postTaskToLoader(PassRefPtr<ScriptExecutionContext::Task>);
+ virtual void postTaskForModeToWorkerContext(PassRefPtr<ScriptExecutionContext::Task>, const String&);
+
+ // WorkerReportingProxy
+ virtual void postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL);
+ virtual void postConsoleMessageToWorkerObject(MessageDestination, MessageSource, MessageType, MessageLevel, const String& message, int lineNumber, const String& sourceURL);
+ virtual void workerContextClosed();
+ virtual void workerContextDestroyed();
// Updates the list of the worker's documents, per section 4.5 of the WebWorkers spec.
void addToWorkerDocuments(ScriptExecutionContext*);
+
+ bool isInWorkerDocuments(Document* document) { return m_workerDocuments.contains(document); }
+
+ // Removes a detached document from the list of worker's documents. May set the closing flag if this is the last document in the list.
+ void documentDetached(Document*);
+
private:
- SharedWorkerProxy(const String& name, const KURL&);
+ SharedWorkerProxy(const String& name, const KURL&, PassRefPtr<SecurityOrigin>);
+ void close();
+
bool m_closing;
String m_name;
KURL m_url;
+ // The thread is freed when the proxy is destroyed, so we need to make sure that the proxy stays around until the SharedWorkerContext exits.
RefPtr<SharedWorkerThread> m_thread;
+ RefPtr<SecurityOrigin> m_origin;
+ HashSet<Document*> m_workerDocuments;
+ // Ensures exclusive access to the worker documents. Must not grab any other locks (such as the DefaultSharedWorkerRepository lock) while holding this one.
+ Mutex m_workerDocumentsLock;
};
-SharedWorkerProxy::SharedWorkerProxy(const String& name, const KURL& url)
+SharedWorkerProxy::SharedWorkerProxy(const String& name, const KURL& url, PassRefPtr<SecurityOrigin> origin)
: m_closing(false)
- , m_name(name.copy())
+ , m_name(name.crossThreadString())
, m_url(url.copy())
+ , m_origin(origin)
+{
+ // We should be the sole owner of the SecurityOrigin, as we will free it on another thread.
+ ASSERT(m_origin->hasOneRef());
+}
+
+bool SharedWorkerProxy::matches(const String& name, PassRefPtr<SecurityOrigin> origin, const KURL& urlToMatch) const
+{
+ // If the origins don't match, or the names don't match, then this is not the proxy we are looking for.
+ if (!origin->equal(m_origin.get()))
+ return false;
+
+ // If the names are both empty, compares the URLs instead per the Web Workers spec.
+ if (name.isEmpty() && m_name.isEmpty())
+ return urlToMatch == url();
+
+ return name == m_name;
+}
+
+void SharedWorkerProxy::postTaskToLoader(PassRefPtr<ScriptExecutionContext::Task> task)
+{
+ MutexLocker lock(m_workerDocumentsLock);
+
+ if (isClosing())
+ return;
+
+ // If we aren't closing, then we must have at least one document.
+ ASSERT(m_workerDocuments.size());
+
+ // Just pick an arbitrary active document from the HashSet and pass load requests to it.
+ // FIXME: Do we need to deal with the case where the user closes the document mid-load, via a shadow document or some other solution?
+ Document* document = *(m_workerDocuments.begin());
+ document->postTask(task);
+}
+
+void SharedWorkerProxy::postTaskForModeToWorkerContext(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode)
+{
+ if (isClosing())
+ return;
+ ASSERT(m_thread);
+ m_thread->runLoop().postTaskForMode(task, mode);
+}
+
+static void postExceptionTask(ScriptExecutionContext* context, const String& errorMessage, int lineNumber, const String& sourceURL)
+{
+ context->reportException(errorMessage, lineNumber, sourceURL);
+}
+
+void SharedWorkerProxy::postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL)
+{
+ MutexLocker lock(m_workerDocumentsLock);
+ for (HashSet<Document*>::iterator iter = m_workerDocuments.begin(); iter != m_workerDocuments.end(); ++iter)
+ (*iter)->postTask(createCallbackTask(&postExceptionTask, errorMessage, lineNumber, sourceURL));
+}
+
+static void postConsoleMessageTask(ScriptExecutionContext* document, MessageDestination destination, MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL)
+{
+ document->addMessage(destination, source, type, level, message, lineNumber, sourceURL);
+}
+
+void SharedWorkerProxy::postConsoleMessageToWorkerObject(MessageDestination destination, MessageSource source, MessageType type, MessageLevel level, const String& message, int lineNumber, const String& sourceURL)
+{
+ MutexLocker lock(m_workerDocumentsLock);
+ for (HashSet<Document*>::iterator iter = m_workerDocuments.begin(); iter != m_workerDocuments.end(); ++iter)
+ (*iter)->postTask(createCallbackTask(&postConsoleMessageTask, destination, source, type, level, message, lineNumber, sourceURL));
+}
+
+void SharedWorkerProxy::workerContextClosed()
+{
+ if (isClosing())
+ return;
+ close();
+}
+
+void SharedWorkerProxy::workerContextDestroyed()
{
+ // The proxy may be freed by this call, so do not reference it any further.
+ DefaultSharedWorkerRepository::instance().removeProxy(this);
}
void SharedWorkerProxy::addToWorkerDocuments(ScriptExecutionContext* context)
{
// Nested workers are not yet supported, so passed-in context should always be a Document.
ASSERT(context->isDocument());
- // FIXME: track referring documents so we can shutdown the thread when the last one exits and remove the proxy from the cache.
+ ASSERT(!isClosing());
+ MutexLocker lock(m_workerDocumentsLock);
+ Document* document = static_cast<Document*>(context);
+ m_workerDocuments.add(document);
+}
+
+void SharedWorkerProxy::documentDetached(Document* document)
+{
+ if (isClosing())
+ return;
+ // Remove the document from our set (if it's there) and if that was the last document in the set, mark the proxy as closed.
+ MutexLocker lock(m_workerDocumentsLock);
+ m_workerDocuments.remove(document);
+ if (!m_workerDocuments.size())
+ close();
+}
+
+void SharedWorkerProxy::close()
+{
+ ASSERT(!isClosing());
+ m_closing = true;
+ // Stop the worker thread - the proxy will stay around until we get workerThreadExited() notification.
+ if (m_thread)
+ m_thread->stop();
}
class SharedWorkerConnectTask : public ScriptExecutionContext::Task {
@@ -109,8 +238,10 @@ private:
port->entangle(m_channel.release());
ASSERT(scriptContext->isWorkerContext());
WorkerContext* workerContext = static_cast<WorkerContext*>(scriptContext);
+ // Since close() stops the thread event loop, this should not ever get called while closing.
+ ASSERT(!workerContext->isClosing());
ASSERT(workerContext->isSharedWorkerContext());
- workerContext->toSharedWorkerContext()->dispatchConnect(port);
+ workerContext->toSharedWorkerContext()->dispatchEvent(createConnectEvent(port));
}
OwnPtr<MessagePortChannel> m_channel;
@@ -145,22 +276,23 @@ void SharedWorkerScriptLoader::load(const KURL& url)
// Mark this object as active for the duration of the load.
ASSERT(!hasPendingActivity());
m_scriptLoader = new WorkerScriptLoader();
- m_scriptLoader->loadAsynchronously(scriptExecutionContext(), url, DenyCrossOriginRedirect, this);
+ m_scriptLoader->loadAsynchronously(scriptExecutionContext(), url, DenyCrossOriginRequests, this);
// Stay alive until the load finishes.
setPendingActivity(this);
+ m_worker->setPendingActivity(m_worker.get());
}
void SharedWorkerScriptLoader::notifyFinished()
{
// Hand off the just-loaded code to the repository to start up the worker thread.
if (m_scriptLoader->failed())
- m_worker->dispatchLoadErrorEvent();
+ m_worker->dispatchEvent(Event::create(eventNames().errorEvent, false, true));
else
DefaultSharedWorkerRepository::instance().workerScriptLoaded(*m_proxy, scriptExecutionContext()->userAgent(m_scriptLoader->url()), m_scriptLoader->script(), m_port.release());
- // This frees this object - must be the last action in this function.
- unsetPendingActivity(this);
+ m_worker->unsetPendingActivity(m_worker.get());
+ unsetPendingActivity(this); // This frees this object - must be the last action in this function.
}
DefaultSharedWorkerRepository& DefaultSharedWorkerRepository::instance()
@@ -172,23 +304,67 @@ DefaultSharedWorkerRepository& DefaultSharedWorkerRepository::instance()
void DefaultSharedWorkerRepository::workerScriptLoaded(SharedWorkerProxy& proxy, const String& userAgent, const String& workerScript, PassOwnPtr<MessagePortChannel> port)
{
MutexLocker lock(m_lock);
- if (proxy.closing())
+ if (proxy.isClosing())
return;
// Another loader may have already started up a thread for this proxy - if so, just send a connect to the pre-existing thread.
if (!proxy.thread()) {
- RefPtr<SharedWorkerThread> thread = SharedWorkerThread::create(proxy.name(), proxy.url(), userAgent, workerScript, proxy);
+ RefPtr<SharedWorkerThread> thread = SharedWorkerThread::create(proxy.name(), proxy.url(), userAgent, workerScript, proxy, proxy);
proxy.setThread(thread);
thread->start();
}
proxy.thread()->runLoop().postTask(SharedWorkerConnectTask::create(port));
}
+bool SharedWorkerRepository::isAvailable()
+{
+ // SharedWorkers are enabled on the default WebKit platform.
+ return true;
+}
+
void SharedWorkerRepository::connect(PassRefPtr<SharedWorker> worker, PassOwnPtr<MessagePortChannel> port, const KURL& url, const String& name, ExceptionCode& ec)
{
DefaultSharedWorkerRepository::instance().connectToWorker(worker, port, url, name, ec);
}
+void SharedWorkerRepository::documentDetached(Document* document)
+{
+ DefaultSharedWorkerRepository::instance().documentDetached(document);
+}
+
+bool SharedWorkerRepository::hasSharedWorkers(Document* document)
+{
+ return DefaultSharedWorkerRepository::instance().hasSharedWorkers(document);
+}
+
+bool DefaultSharedWorkerRepository::hasSharedWorkers(Document* document)
+{
+ MutexLocker lock(m_lock);
+ for (unsigned i = 0; i < m_proxies.size(); i++) {
+ if (m_proxies[i]->isInWorkerDocuments(document))
+ return true;
+ }
+ return false;
+}
+
+void DefaultSharedWorkerRepository::removeProxy(SharedWorkerProxy* proxy)
+{
+ MutexLocker lock(m_lock);
+ for (unsigned i = 0; i < m_proxies.size(); i++) {
+ if (proxy == m_proxies[i].get()) {
+ m_proxies.remove(i);
+ return;
+ }
+ }
+}
+
+void DefaultSharedWorkerRepository::documentDetached(Document* document)
+{
+ MutexLocker lock(m_lock);
+ for (unsigned i = 0; i < m_proxies.size(); i++)
+ m_proxies[i]->documentDetached(document);
+}
+
void DefaultSharedWorkerRepository::connectToWorker(PassRefPtr<SharedWorker> worker, PassOwnPtr<MessagePortChannel> port, const KURL& url, const String& name, ExceptionCode& ec)
{
MutexLocker lock(m_lock);
@@ -214,20 +390,17 @@ void DefaultSharedWorkerRepository::connectToWorker(PassRefPtr<SharedWorker> wor
PassRefPtr<SharedWorkerProxy> DefaultSharedWorkerRepository::getProxy(const String& name, const KURL& url)
{
// Look for an existing worker, and create one if it doesn't exist.
- // Items in the cache are freed on another thread, so copy the URL before creating the origin, to make sure no references to external strings linger.
- RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url.copy());
- SharedWorkerNameMap* nameMap = m_cache.get(origin);
- if (!nameMap) {
- nameMap = new SharedWorkerNameMap();
- m_cache.set(origin, nameMap);
- }
-
- RefPtr<SharedWorkerProxy> proxy = nameMap->get(name);
- if (!proxy.get()) {
- proxy = SharedWorkerProxy::create(name, url);
- nameMap->set(proxy->name(), proxy);
+ // Items in the cache are freed on another thread, so do a threadsafe copy of the URL before creating the origin,
+ // to make sure no references to external strings linger.
+ RefPtr<SecurityOrigin> origin = SecurityOrigin::create(KURL(ParsedURLString, url.string().threadsafeCopy()));
+ for (unsigned i = 0; i < m_proxies.size(); i++) {
+ if (!m_proxies[i]->isClosing() && m_proxies[i]->matches(name, origin, url))
+ return m_proxies[i];
}
- return proxy;
+ // Proxy is not in the repository currently - create a new one.
+ RefPtr<SharedWorkerProxy> proxy = SharedWorkerProxy::create(name, url, origin.release());
+ m_proxies.append(proxy);
+ return proxy.release();
}
DefaultSharedWorkerRepository::DefaultSharedWorkerRepository()
diff --git a/WebCore/workers/DefaultSharedWorkerRepository.h b/WebCore/workers/DefaultSharedWorkerRepository.h
index 0b4e66c..c2eaff4 100644
--- a/WebCore/workers/DefaultSharedWorkerRepository.h
+++ b/WebCore/workers/DefaultSharedWorkerRepository.h
@@ -33,22 +33,24 @@
#if ENABLE(SHARED_WORKERS)
-#include "SharedWorkerRepository.h"
+#include "ExceptionCode.h"
#include "StringHash.h"
#include <wtf/HashMap.h>
#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/Threading.h>
namespace WebCore {
+ class Document;
class KURL;
+ class MessagePortChannel;
class ScriptExecutionContext;
- class SecurityOrigin;
+ class SharedWorker;
class SharedWorkerProxy;
-
- struct SecurityOriginHash;
- struct SecurityOriginTraits;
+ class String;
// Platform-specific implementation of the SharedWorkerRepository static interface.
class DefaultSharedWorkerRepository : public Noncopyable {
@@ -59,6 +61,14 @@ namespace WebCore {
// Internal implementation of SharedWorkerRepository::connect()
void connectToWorker(PassRefPtr<SharedWorker>, PassOwnPtr<MessagePortChannel>, const KURL&, const String& name, ExceptionCode&);
+ // Notification that a document has been detached.
+ void documentDetached(Document*);
+
+ // Removes the passed SharedWorkerProxy from the repository.
+ void removeProxy(SharedWorkerProxy*);
+
+ bool hasSharedWorkers(Document*);
+
static DefaultSharedWorkerRepository& instance();
private:
DefaultSharedWorkerRepository();
@@ -68,11 +78,9 @@ namespace WebCore {
// Mutex used to protect internal data structures.
Mutex m_lock;
- typedef HashMap<String, RefPtr<SharedWorkerProxy> > SharedWorkerNameMap;
- typedef HashMap<RefPtr<SecurityOrigin>, SharedWorkerNameMap*, SecurityOriginHash> SharedWorkerProxyCache;
-
- // Items in this cache may be freed on another thread, so all keys and values must be either copied before insertion or thread safe.
- SharedWorkerProxyCache m_cache;
+ // List of shared workers. Expectation is that there will be a limited number of shared workers, and so tracking them in a Vector is more efficient than nested HashMaps.
+ typedef Vector<RefPtr<SharedWorkerProxy> > SharedWorkerProxyRepository;
+ SharedWorkerProxyRepository m_proxies;
};
} // namespace WebCore
diff --git a/WebCore/workers/SharedWorkerContext.cpp b/WebCore/workers/SharedWorkerContext.cpp
index 2c50d94..cd76e3b 100644
--- a/WebCore/workers/SharedWorkerContext.cpp
+++ b/WebCore/workers/SharedWorkerContext.cpp
@@ -39,10 +39,16 @@
#include "MessageEvent.h"
#include "NotImplemented.h"
#include "SharedWorkerThread.h"
-#include "WorkerObjectProxy.h"
namespace WebCore {
+PassRefPtr<MessageEvent> createConnectEvent(PassRefPtr<MessagePort> port)
+{
+ RefPtr<MessageEvent> event = MessageEvent::create(new MessagePortArray(1, port));
+ event->initEvent(eventNames().connectEvent, false, false);
+ return event;
+}
+
SharedWorkerContext::SharedWorkerContext(const String& name, const KURL& url, const String& userAgent, SharedWorkerThread* thread)
: WorkerContext(url, userAgent, thread)
, m_name(name)
@@ -53,36 +59,6 @@ SharedWorkerContext::~SharedWorkerContext()
{
}
-void SharedWorkerContext::forwardException(const String&, int, const String&)
-{
- // FIXME: forward to console (do not need to report to parent context).
-}
-
-void SharedWorkerContext::addMessage(MessageDestination, MessageSource, MessageType, MessageLevel, const String&, unsigned, const String&)
-{
- // FIXME: forward to console.
- notImplemented();
-}
-
-void SharedWorkerContext::dispatchConnect(PassRefPtr<MessagePort> port)
-{
- // Since close() stops the thread event loop, this should not ever get called while closing.
- ASSERT(!isClosing());
- // The connect event uses the MessageEvent interface, but has the name "connect".
- RefPtr<Event> event = MessageEvent::create("", "", "", 0, port);
- event->initEvent(eventNames().connectEvent, false, false);
-
- if (m_onconnectListener.get()) {
- event->setTarget(this);
- event->setCurrentTarget(this);
- m_onconnectListener->handleEvent(event.get(), false);
- }
-
- ExceptionCode ec = 0;
- dispatchEvent(event.release(), ec);
- ASSERT(!ec);
-}
-
SharedWorkerThread* SharedWorkerContext::thread()
{
return static_cast<SharedWorkerThread*>(Base::thread());
diff --git a/WebCore/workers/SharedWorkerContext.h b/WebCore/workers/SharedWorkerContext.h
index a7e4133..59a7605 100644
--- a/WebCore/workers/SharedWorkerContext.h
+++ b/WebCore/workers/SharedWorkerContext.h
@@ -37,6 +37,7 @@
namespace WebCore {
+ class MessageEvent;
class SharedWorkerThread;
class SharedWorkerContext : public WorkerContext {
@@ -50,28 +51,21 @@ namespace WebCore {
virtual bool isSharedWorkerContext() const { return true; }
- // ScriptExecutionContext
- virtual void addMessage(MessageDestination, MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL);
-
- virtual void forwardException(const String& errorMessage, int lineNumber, const String& sourceURL);
-
// EventTarget
virtual SharedWorkerContext* toSharedWorkerContext() { return this; }
// Setters/Getters for attributes in SharedWorkerContext.idl
- void setOnconnect(PassRefPtr<EventListener> eventListener) { m_onconnectListener = eventListener; }
- EventListener* onconnect() const { return m_onconnectListener.get(); }
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(connect);
String name() const { return m_name; }
- void dispatchConnect(PassRefPtr<MessagePort>);
-
SharedWorkerThread* thread();
private:
SharedWorkerContext(const String& name, const KURL&, const String&, SharedWorkerThread*);
- RefPtr<EventListener> m_onconnectListener;
String m_name;
};
+ PassRefPtr<MessageEvent> createConnectEvent(PassRefPtr<MessagePort>);
+
} // namespace WebCore
#endif // ENABLE(SHARED_WORKERS)
diff --git a/WebCore/workers/SharedWorkerContext.idl b/WebCore/workers/SharedWorkerContext.idl
index 8e450e0..a48e5bd 100644
--- a/WebCore/workers/SharedWorkerContext.idl
+++ b/WebCore/workers/SharedWorkerContext.idl
@@ -32,7 +32,6 @@ module threads {
interface [
Conditional=SHARED_WORKERS,
- CustomMarkFunction,
ExtendsDOMGlobalObject,
IsWorkerContext,
GenerateNativeConverter,
diff --git a/WebCore/workers/SharedWorkerRepository.h b/WebCore/workers/SharedWorkerRepository.h
index 84acf77..49f3941 100644
--- a/WebCore/workers/SharedWorkerRepository.h
+++ b/WebCore/workers/SharedWorkerRepository.h
@@ -34,12 +34,12 @@
#if ENABLE(SHARED_WORKERS)
#include "ExceptionCode.h"
-
#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
namespace WebCore {
+ class Document;
class KURL;
class MessagePortChannel;
class SharedWorker;
@@ -48,8 +48,17 @@ namespace WebCore {
// Interface to a repository which manages references to the set of active shared workers.
class SharedWorkerRepository {
public:
+ // Returns true if the platform supports SharedWorkers, otherwise false.
+ static bool isAvailable();
+
// Connects the passed SharedWorker object with the specified worker thread, creating a new thread if necessary.
static void connect(PassRefPtr<SharedWorker>, PassOwnPtr<MessagePortChannel>, const KURL&, const String& name, ExceptionCode&);
+
+ // Invoked when a document has been detached.
+ static void documentDetached(Document*);
+
+ // Returns true if the passed document is associated with any SharedWorkers.
+ static bool hasSharedWorkers(Document*);
private:
SharedWorkerRepository() { }
};
diff --git a/WebCore/workers/SharedWorkerThread.cpp b/WebCore/workers/SharedWorkerThread.cpp
index 40bb2de..e59df4f 100644
--- a/WebCore/workers/SharedWorkerThread.cpp
+++ b/WebCore/workers/SharedWorkerThread.cpp
@@ -38,14 +38,14 @@
namespace WebCore {
-PassRefPtr<SharedWorkerThread> SharedWorkerThread::create(const String& name, const KURL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy)
+PassRefPtr<SharedWorkerThread> SharedWorkerThread::create(const String& name, const KURL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy)
{
- return adoptRef(new SharedWorkerThread(name, scriptURL, userAgent, sourceCode, workerLoaderProxy));
+ return adoptRef(new SharedWorkerThread(name, scriptURL, userAgent, sourceCode, workerLoaderProxy, workerReportingProxy));
}
-SharedWorkerThread::SharedWorkerThread(const String& name, const KURL& url, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy)
- : WorkerThread(url, userAgent, sourceCode, workerLoaderProxy)
- , m_name(name.copy())
+SharedWorkerThread::SharedWorkerThread(const String& name, const KURL& url, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy)
+ : WorkerThread(url, userAgent, sourceCode, workerLoaderProxy, workerReportingProxy)
+ , m_name(name.crossThreadString())
{
}
diff --git a/WebCore/workers/SharedWorkerThread.h b/WebCore/workers/SharedWorkerThread.h
index 15838d7..d96fd2a 100644
--- a/WebCore/workers/SharedWorkerThread.h
+++ b/WebCore/workers/SharedWorkerThread.h
@@ -38,14 +38,14 @@ namespace WebCore {
class SharedWorkerThread : public WorkerThread {
public:
- static PassRefPtr<SharedWorkerThread> create(const String& name, const KURL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&);
+ static PassRefPtr<SharedWorkerThread> create(const String& name, const KURL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerReportingProxy&);
~SharedWorkerThread();
protected:
virtual PassRefPtr<WorkerContext> createWorkerContext(const KURL&, const String&);
private:
- SharedWorkerThread(const String& name, const KURL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&);
+ SharedWorkerThread(const String& name, const KURL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerReportingProxy&);
String m_name;
};
diff --git a/WebCore/workers/Worker.cpp b/WebCore/workers/Worker.cpp
index a906134..864b7c6 100644
--- a/WebCore/workers/Worker.cpp
+++ b/WebCore/workers/Worker.cpp
@@ -58,7 +58,7 @@ Worker::Worker(const String& url, ScriptExecutionContext* context, ExceptionCode
return;
m_scriptLoader = new WorkerScriptLoader();
- m_scriptLoader->loadAsynchronously(scriptExecutionContext(), scriptURL, DenyCrossOriginRedirect, this);
+ m_scriptLoader->loadAsynchronously(scriptExecutionContext(), scriptURL, DenyCrossOriginRequests, this);
setPendingActivity(this); // The worker context does not exist while loading, so we must ensure that the worker object is not collected, as well as its event listeners.
}
@@ -69,18 +69,27 @@ Worker::~Worker()
m_contextProxy->workerObjectDestroyed();
}
-void Worker::postMessage(const String& message, ExceptionCode& ec)
+// FIXME: remove this when we update the ObjC bindings (bug #28774).
+void Worker::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, ExceptionCode& ec)
{
- postMessage(message, 0, ec);
+ MessagePortArray ports;
+ if (port)
+ ports.append(port);
+ postMessage(message, &ports, ec);
}
-void Worker::postMessage(const String& message, MessagePort* messagePort, ExceptionCode& ec)
+void Worker::postMessage(PassRefPtr<SerializedScriptValue> message, ExceptionCode& ec)
+{
+ postMessage(message, static_cast<MessagePortArray*>(0), ec);
+}
+
+void Worker::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, ExceptionCode& ec)
{
// Disentangle the port in preparation for sending it to the remote context.
- OwnPtr<MessagePortChannel> channel = messagePort ? messagePort->disentangle(ec) : 0;
+ OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec);
if (ec)
return;
- m_contextProxy->postMessageToWorkerContext(message, channel.release());
+ m_contextProxy->postMessageToWorkerContext(message, channels.release());
}
void Worker::terminate()
@@ -107,7 +116,7 @@ bool Worker::hasPendingActivity() const
void Worker::notifyFinished()
{
if (m_scriptLoader->failed())
- dispatchLoadErrorEvent();
+ dispatchEvent(Event::create(eventNames().errorEvent, false, true));
else
m_contextProxy->startWorkerContext(m_scriptLoader->url(), scriptExecutionContext()->userAgent(m_scriptLoader->url()), m_scriptLoader->script());
@@ -116,21 +125,6 @@ void Worker::notifyFinished()
unsetPendingActivity(this);
}
-void Worker::dispatchMessage(const String& message, PassRefPtr<MessagePort> port)
-{
- RefPtr<Event> evt = MessageEvent::create(message, "", "", 0, port);
-
- 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);
-}
-
} // namespace WebCore
#endif // ENABLE(WORKERS)
diff --git a/WebCore/workers/Worker.h b/WebCore/workers/Worker.h
index 66a8ae9..6b8fa84 100644
--- a/WebCore/workers/Worker.h
+++ b/WebCore/workers/Worker.h
@@ -33,7 +33,9 @@
#include "ActiveDOMObject.h"
#include "AtomicStringHash.h"
#include "EventListener.h"
+#include "EventNames.h"
#include "EventTarget.h"
+#include "MessagePort.h"
#include "WorkerScriptLoaderClient.h"
#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
@@ -56,20 +58,18 @@ namespace WebCore {
virtual Worker* toWorker() { return this; }
- void postMessage(const String&, ExceptionCode&);
- void postMessage(const String&, MessagePort*, ExceptionCode&);
+ void postMessage(PassRefPtr<SerializedScriptValue>, ExceptionCode&);
+ void postMessage(PassRefPtr<SerializedScriptValue>, const MessagePortArray*, ExceptionCode&);
+ // FIXME: remove this when we update the ObjC bindings (bug #28774).
+ void postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort*, ExceptionCode&);
void terminate();
- void dispatchMessage(const String&, PassRefPtr<MessagePort>);
- void dispatchErrorEvent();
-
virtual bool canSuspend() const;
virtual void stop();
virtual bool hasPendingActivity() const;
-
- void setOnmessage(PassRefPtr<EventListener> eventListener) { m_onMessageListener = eventListener; }
- EventListener* onmessage() const { return m_onMessageListener.get(); }
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(message);
private:
Worker(const String&, ScriptExecutionContext*, ExceptionCode&);
@@ -80,10 +80,7 @@ namespace WebCore {
virtual void derefEventTarget() { deref(); }
OwnPtr<WorkerScriptLoader> m_scriptLoader;
-
WorkerContextProxy* m_contextProxy; // The proxy outlives the worker to perform thread shutdown.
-
- RefPtr<EventListener> m_onMessageListener;
};
} // namespace WebCore
diff --git a/WebCore/workers/Worker.idl b/WebCore/workers/Worker.idl
index e701523..0382739 100644
--- a/WebCore/workers/Worker.idl
+++ b/WebCore/workers/Worker.idl
@@ -28,14 +28,20 @@ module threads {
interface [
Conditional=WORKERS,
- CustomMarkFunction,
GenerateNativeConverter,
GenerateToJS
] Worker : AbstractWorker {
attribute EventListener onmessage;
- void postMessage(in DOMString message, in [Optional] MessagePort messagePort)
+
+#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
+ [Custom] void postMessage(in SerialisedScriptValue message, in [Optional] Array messagePorts)
+ raises(DOMException);
+#else
+ // There's no good way to expose an array via the ObjC bindings, so for now just allow passing in a single port.
+ void postMessage(in SerializedScriptValue message, in [Optional] MessagePort messagePort)
raises(DOMException);
+#endif
void terminate();
};
diff --git a/WebCore/workers/WorkerContext.cpp b/WebCore/workers/WorkerContext.cpp
index 722588f..f85dd8e 100644
--- a/WebCore/workers/WorkerContext.cpp
+++ b/WebCore/workers/WorkerContext.cpp
@@ -49,6 +49,13 @@
#include "WorkerThreadableLoader.h"
#include "XMLHttpRequestException.h"
#include <wtf/RefPtr.h>
+#if PLATFORM(ANDROID)
+#include <wtf/UnusedParam.h>
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+#include "NotificationCenter.h"
+#endif
namespace WebCore {
@@ -64,6 +71,12 @@ WorkerContext::WorkerContext(const KURL& url, const String& userAgent, WorkerThr
WorkerContext::~WorkerContext()
{
+ ASSERT(currentThread() == thread()->threadID());
+#if ENABLE(NOTIFICATIONS)
+ m_notifications.clear();
+#endif
+ // Notify proxy that we are going away. This can free the WorkerThread object, so do not access it after this.
+ thread()->workerReportingProxy().workerContextDestroyed();
}
ScriptExecutionContext* WorkerContext::scriptExecutionContext() const
@@ -109,7 +122,8 @@ void WorkerContext::close()
return;
m_closing = true;
- m_thread->stop();
+ // Notify parent that this context is closed. Parent is responsible for calling WorkerThread::stop().
+ thread()->workerReportingProxy().workerContextClosed();
}
WorkerNavigator* WorkerContext::navigator() const
@@ -150,57 +164,6 @@ void WorkerContext::scriptImported(unsigned long, const String&)
notImplemented();
}
-void WorkerContext::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 WorkerContext::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 WorkerContext::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 WorkerContext::postTask(PassRefPtr<Task> task)
{
thread()->runLoop().postTask(task);
@@ -228,6 +191,10 @@ void WorkerContext::clearInterval(int timeoutId)
void WorkerContext::importScripts(const Vector<String>& urls, const String& callerURL, int callerLine, ExceptionCode& ec)
{
+#if !ENABLE(INSPECTOR)
+ UNUSED_PARAM(callerURL);
+ UNUSED_PARAM(callerLine);
+#endif
ec = 0;
Vector<String>::const_iterator urlsEnd = urls.end();
Vector<KURL> completedURLs;
@@ -239,12 +206,11 @@ void WorkerContext::importScripts(const Vector<String>& urls, const String& call
}
completedURLs.append(url);
}
- String securityOrigin = scriptExecutionContext()->securityOrigin()->toString();
Vector<KURL>::const_iterator end = completedURLs.end();
for (Vector<KURL>::const_iterator it = completedURLs.begin(); it != end; ++it) {
WorkerScriptLoader scriptLoader;
- scriptLoader.loadSynchronously(scriptExecutionContext(), *it, AllowCrossOriginRedirect);
+ scriptLoader.loadSynchronously(scriptExecutionContext(), *it, AllowCrossOriginRequests);
// If the fetching attempt failed, throw a NETWORK_ERR exception and abort all these steps.
if (scriptLoader.failed()) {
@@ -253,7 +219,9 @@ void WorkerContext::importScripts(const Vector<String>& urls, const String& call
}
scriptExecutionContext()->scriptImported(scriptLoader.identifier(), scriptLoader.script());
+#if ENABLE(INSPECTOR)
scriptExecutionContext()->addMessage(InspectorControllerDestination, JSMessageSource, LogMessageType, LogMessageLevel, "Worker script imported: \"" + *it + "\".", callerLine, callerURL);
+#endif
ScriptValue exception;
m_script->evaluate(ScriptSourceCode(scriptLoader.script(), *it), &exception);
@@ -268,10 +236,34 @@ void WorkerContext::reportException(const String& errorMessage, int lineNumber,
{
bool errorHandled = false;
if (onerror())
- errorHandled = onerror()->reportError(errorMessage, sourceURL, lineNumber);
+ errorHandled = onerror()->reportError(this, errorMessage, sourceURL, lineNumber);
if (!errorHandled)
- forwardException(errorMessage, lineNumber, sourceURL);
+ thread()->workerReportingProxy().postExceptionToWorkerObject(errorMessage, lineNumber, sourceURL);
+}
+
+void WorkerContext::addMessage(MessageDestination destination, MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL)
+{
+ thread()->workerReportingProxy().postConsoleMessageToWorkerObject(destination, source, type, level, message, lineNumber, sourceURL);
+}
+
+#if ENABLE(NOTIFICATIONS)
+NotificationCenter* WorkerContext::webkitNotifications() const
+{
+ if (!m_notifications)
+ m_notifications = NotificationCenter::create(scriptExecutionContext(), m_thread->getNotificationPresenter());
+ return m_notifications.get();
+}
+#endif
+
+EventTargetData* WorkerContext::eventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+EventTargetData* WorkerContext::ensureEventTargetData()
+{
+ return &m_eventTargetData;
}
} // namespace WebCore
diff --git a/WebCore/workers/WorkerContext.h b/WebCore/workers/WorkerContext.h
index aa47475..9725cf7 100644
--- a/WebCore/workers/WorkerContext.h
+++ b/WebCore/workers/WorkerContext.h
@@ -31,6 +31,7 @@
#include "AtomicStringHash.h"
#include "EventListener.h"
+#include "EventNames.h"
#include "EventTarget.h"
#include "ScriptExecutionContext.h"
#include "WorkerScriptController.h"
@@ -41,6 +42,7 @@
namespace WebCore {
+ class NotificationCenter;
class ScheduledAction;
class WorkerLocation;
class WorkerNavigator;
@@ -48,7 +50,6 @@ namespace WebCore {
class WorkerContext : public RefCounted<WorkerContext>, public ScriptExecutionContext, public EventTarget {
public:
-
virtual ~WorkerContext();
virtual bool isWorkerContext() const { return true; }
@@ -79,8 +80,8 @@ namespace WebCore {
WorkerContext* self() { return this; }
WorkerLocation* location() const;
void close();
- void setOnerror(PassRefPtr<EventListener> eventListener) { m_onerrorListener = eventListener; }
- EventListener* onerror() const { return m_onerrorListener.get(); }
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
// WorkerUtils
virtual void importScripts(const Vector<String>& urls, const String& callerURL, int callerLine, ExceptionCode&);
@@ -92,19 +93,13 @@ namespace WebCore {
int setInterval(ScheduledAction*, int timeout);
void clearInterval(int timeoutId);
- // EventTarget
- virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
- virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
- virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&);
-
- typedef Vector<RefPtr<EventListener> > ListenerVector;
- typedef HashMap<AtomicString, ListenerVector> EventListenersMap;
- EventListenersMap& eventListeners() { return m_eventListeners; }
-
// ScriptExecutionContext
virtual void reportException(const String& errorMessage, int lineNumber, const String& sourceURL);
+ virtual void addMessage(MessageDestination, MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL);
- virtual void forwardException(const String& errorMessage, int lineNumber, const String& sourceURL) = 0;
+#if ENABLE(NOTIFICATIONS)
+ NotificationCenter* webkitNotifications() const;
+#endif
// These methods are used for GC marking. See JSWorkerContext::markChildren(MarkStack&) in
// JSWorkerContextCustom.cpp.
@@ -114,15 +109,19 @@ namespace WebCore {
using RefCounted<WorkerContext>::ref;
using RefCounted<WorkerContext>::deref;
+ bool isClosing() { return m_closing; }
+
protected:
WorkerContext(const KURL&, const String&, WorkerThread*);
- bool isClosing() { return m_closing; }
private:
virtual void refScriptExecutionContext() { ref(); }
virtual void derefScriptExecutionContext() { deref(); }
+
virtual void refEventTarget() { ref(); }
virtual void derefEventTarget() { deref(); }
+ virtual EventTargetData* eventTargetData();
+ virtual EventTargetData* ensureEventTargetData();
virtual const KURL& virtualURL() const;
virtual KURL virtualCompleteURL(const String&) const;
@@ -136,10 +135,11 @@ namespace WebCore {
OwnPtr<WorkerScriptController> m_script;
WorkerThread* m_thread;
- RefPtr<EventListener> m_onerrorListener;
- EventListenersMap m_eventListeners;
-
+#if ENABLE_NOTIFICATIONS
+ mutable RefPtr<NotificationCenter> m_notifications;
+#endif
bool m_closing;
+ EventTargetData m_eventTargetData;
};
} // namespace WebCore
diff --git a/WebCore/workers/WorkerContext.idl b/WebCore/workers/WorkerContext.idl
index 2404d22..17bee55 100644
--- a/WebCore/workers/WorkerContext.idl
+++ b/WebCore/workers/WorkerContext.idl
@@ -30,6 +30,7 @@ module threads {
Conditional=WORKERS,
CustomMarkFunction,
DelegatingGetOwnPropertySlot,
+ EventTarget,
ExtendsDOMGlobalObject,
IsWorkerContext,
LegacyParent=JSWorkerContextBase,
@@ -69,6 +70,10 @@ module threads {
boolean dispatchEvent(in Event evt)
raises(EventException);
+#if defined(ENABLE_NOTIFICATIONS) && ENABLE_NOTIFICATIONS
+ // Notification interface
+ readonly attribute NotificationCenter webkitNotifications;
+#endif
// Constructors
attribute MessageEventConstructor MessageEvent;
@@ -77,6 +82,9 @@ module threads {
#if ENABLE_CHANNEL_MESSAGING
attribute [JSCCustomGetter] MessageChannelConstructor MessageChannel;
#endif
+#if ENABLE_EVENTSOURCE
+ attribute [JSCCustomGetter] EventSourceConstructor EventSource;
+#endif
attribute [JSCCustomGetter] XMLHttpRequestConstructor XMLHttpRequest;
};
diff --git a/WebCore/workers/WorkerContextProxy.h b/WebCore/workers/WorkerContextProxy.h
index f42527e..e1ca139 100644
--- a/WebCore/workers/WorkerContextProxy.h
+++ b/WebCore/workers/WorkerContextProxy.h
@@ -33,12 +33,12 @@
#if ENABLE(WORKERS)
+#include "MessagePort.h"
#include <wtf/PassOwnPtr.h>
namespace WebCore {
class KURL;
- class MessagePortChannel;
class String;
class Worker;
@@ -53,7 +53,7 @@ namespace WebCore {
virtual void terminateWorkerContext() = 0;
- virtual void postMessageToWorkerContext(const String&, PassOwnPtr<MessagePortChannel>) = 0;
+ virtual void postMessageToWorkerContext(PassRefPtr<SerializedScriptValue>, PassOwnPtr<MessagePortChannelArray>) = 0;
virtual bool hasPendingActivity() const = 0;
diff --git a/WebCore/workers/WorkerMessagingProxy.cpp b/WebCore/workers/WorkerMessagingProxy.cpp
index 1dac28e..0b66694 100644
--- a/WebCore/workers/WorkerMessagingProxy.cpp
+++ b/WebCore/workers/WorkerMessagingProxy.cpp
@@ -35,6 +35,8 @@
#include "DedicatedWorkerThread.h"
#include "DOMWindow.h"
#include "Document.h"
+#include "ErrorEvent.h"
+#include "ExceptionCode.h"
#include "GenericWorkerTask.h"
#include "MessageEvent.h"
#include "ScriptExecutionContext.h"
@@ -44,15 +46,15 @@ namespace WebCore {
class MessageWorkerContextTask : public ScriptExecutionContext::Task {
public:
- static PassRefPtr<MessageWorkerContextTask> create(const String& message, PassOwnPtr<MessagePortChannel> channel)
+ static PassRefPtr<MessageWorkerContextTask> create(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
{
- return adoptRef(new MessageWorkerContextTask(message, channel));
+ return adoptRef(new MessageWorkerContextTask(message, channels));
}
private:
- MessageWorkerContextTask(const String& message, PassOwnPtr<MessagePortChannel> channel)
- : m_message(message.copy())
- , m_channel(channel)
+ MessageWorkerContextTask(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
+ : m_message(message->release())
+ , m_channels(channels)
{
}
@@ -60,31 +62,27 @@ private:
{
ASSERT(scriptContext->isWorkerContext());
DedicatedWorkerContext* context = static_cast<DedicatedWorkerContext*>(scriptContext);
- RefPtr<MessagePort> port;
- if (m_channel) {
- port = MessagePort::create(*scriptContext);
- port->entangle(m_channel.release());
- }
- context->dispatchMessage(m_message, port.release());
+ OwnPtr<MessagePortArray> ports = MessagePort::entanglePorts(*scriptContext, m_channels.release());
+ context->dispatchEvent(MessageEvent::create(ports.release(), m_message));
context->thread()->workerObjectProxy().confirmMessageFromWorkerObject(context->hasPendingActivity());
}
private:
- String m_message;
- OwnPtr<MessagePortChannel> m_channel;
+ RefPtr<SerializedScriptValue> m_message;
+ OwnPtr<MessagePortChannelArray> m_channels;
};
class MessageWorkerTask : public ScriptExecutionContext::Task {
public:
- static PassRefPtr<MessageWorkerTask> create(const String& message, PassOwnPtr<MessagePortChannel> channel, WorkerMessagingProxy* messagingProxy)
+ static PassRefPtr<MessageWorkerTask> create(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels, WorkerMessagingProxy* messagingProxy)
{
- return adoptRef(new MessageWorkerTask(message, channel, messagingProxy));
+ return adoptRef(new MessageWorkerTask(message, channels, messagingProxy));
}
private:
- MessageWorkerTask(const String& message, PassOwnPtr<MessagePortChannel> channel, WorkerMessagingProxy* messagingProxy)
- : m_message(message.copy())
- , m_channel(channel)
+ MessageWorkerTask(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels, WorkerMessagingProxy* messagingProxy)
+ : m_message(message->release())
+ , m_channels(channels)
, m_messagingProxy(messagingProxy)
{
}
@@ -95,17 +93,13 @@ private:
if (!workerObject || m_messagingProxy->askedToTerminate())
return;
- RefPtr<MessagePort> port;
- if (m_channel) {
- port = MessagePort::create(*scriptContext);
- port->entangle(m_channel.release());
- }
- workerObject->dispatchMessage(m_message, port.release());
+ OwnPtr<MessagePortArray> ports = MessagePort::entanglePorts(*scriptContext, m_channels.release());
+ workerObject->dispatchEvent(MessageEvent::create(ports.release(), m_message));
}
private:
- String m_message;
- OwnPtr<MessagePortChannel> m_channel;
+ RefPtr<SerializedScriptValue> m_message;
+ OwnPtr<MessagePortChannelArray> m_channels;
WorkerMessagingProxy* m_messagingProxy;
};
@@ -118,9 +112,9 @@ public:
private:
WorkerExceptionTask(const String& errorMessage, int lineNumber, const String& sourceURL, WorkerMessagingProxy* messagingProxy)
- : m_errorMessage(errorMessage.copy())
+ : m_errorMessage(errorMessage.crossThreadString())
, m_lineNumber(lineNumber)
- , m_sourceURL(sourceURL.copy())
+ , m_sourceURL(sourceURL.crossThreadString())
, m_messagingProxy(messagingProxy)
{
}
@@ -128,13 +122,13 @@ private:
virtual void performTask(ScriptExecutionContext* context)
{
Worker* workerObject = m_messagingProxy->workerObject();
- if (!workerObject || m_messagingProxy->askedToTerminate())
+ if (!workerObject)
return;
- bool errorHandled = false;
- if (workerObject->onerror())
- errorHandled = workerObject->dispatchScriptErrorEvent(m_errorMessage, m_sourceURL, m_lineNumber);
+ // We don't bother checking the askedToTerminate() flag here, because exceptions should *always* be reported even if the thread is terminated.
+ // This is intentionally different than the behavior in MessageWorkerTask, because terminated workers no longer deliver messages (section 4.6 of the WebWorker spec), but they do report exceptions.
+ bool errorHandled = !workerObject->dispatchEvent(ErrorEvent::create(m_errorMessage, m_sourceURL, m_lineNumber));
if (!errorHandled)
context->reportException(m_errorMessage, m_lineNumber, m_sourceURL);
}
@@ -166,6 +160,27 @@ private:
WorkerMessagingProxy* m_messagingProxy;
};
+class WorkerTerminateTask : public ScriptExecutionContext::Task {
+public:
+ static PassRefPtr<WorkerTerminateTask> create(WorkerMessagingProxy* messagingProxy)
+ {
+ return adoptRef(new WorkerTerminateTask(messagingProxy));
+ }
+
+private:
+ WorkerTerminateTask(WorkerMessagingProxy* messagingProxy)
+ : m_messagingProxy(messagingProxy)
+ {
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ m_messagingProxy->terminateWorkerContext();
+ }
+
+ WorkerMessagingProxy* m_messagingProxy;
+};
+
class WorkerThreadActivityReportTask : public ScriptExecutionContext::Task {
public:
static PassRefPtr<WorkerThreadActivityReportTask> create(WorkerMessagingProxy* messagingProxy, bool confirmingMessage, bool hasPendingActivity)
@@ -225,21 +240,21 @@ void WorkerMessagingProxy::startWorkerContext(const KURL& scriptURL, const Strin
thread->start();
}
-void WorkerMessagingProxy::postMessageToWorkerObject(const String& message, PassOwnPtr<MessagePortChannel> channel)
+void WorkerMessagingProxy::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
{
- m_scriptExecutionContext->postTask(MessageWorkerTask::create(message, channel, this));
+ m_scriptExecutionContext->postTask(MessageWorkerTask::create(message, channels.release(), this));
}
-void WorkerMessagingProxy::postMessageToWorkerContext(const String& message, PassOwnPtr<MessagePortChannel> channel)
+void WorkerMessagingProxy::postMessageToWorkerContext(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
{
if (m_askedToTerminate)
return;
if (m_workerThread) {
++m_unconfirmedMessageCount;
- m_workerThread->runLoop().postTask(MessageWorkerContextTask::create(message, channel));
+ m_workerThread->runLoop().postTask(MessageWorkerContextTask::create(message, channels.release()));
} else
- m_queuedEarlyTasks.append(MessageWorkerContextTask::create(message, channel));
+ m_queuedEarlyTasks.append(MessageWorkerContextTask::create(message, channels.release()));
}
void WorkerMessagingProxy::postTaskForModeToWorkerContext(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode)
@@ -309,6 +324,12 @@ void WorkerMessagingProxy::workerContextDestroyed()
// Will execute workerContextDestroyedInternal() on context's thread.
}
+void WorkerMessagingProxy::workerContextClosed()
+{
+ // Executes terminateWorkerContext() on parent context's thread.
+ m_scriptExecutionContext->postTask(WorkerTerminateTask::create(this));
+}
+
void WorkerMessagingProxy::workerContextDestroyedInternal()
{
// WorkerContextDestroyedTask is always the last to be performed, so the proxy is not needed for communication
diff --git a/WebCore/workers/WorkerMessagingProxy.h b/WebCore/workers/WorkerMessagingProxy.h
index 841fc9a..754102a 100644
--- a/WebCore/workers/WorkerMessagingProxy.h
+++ b/WebCore/workers/WorkerMessagingProxy.h
@@ -42,7 +42,6 @@
namespace WebCore {
class DedicatedWorkerThread;
- class MessagePortChannel;
class ScriptExecutionContext;
class String;
class Worker;
@@ -55,17 +54,18 @@ namespace WebCore {
// (Only use these methods in the worker object thread.)
virtual void startWorkerContext(const KURL& scriptURL, const String& userAgent, const String& sourceCode);
virtual void terminateWorkerContext();
- virtual void postMessageToWorkerContext(const String&, PassOwnPtr<MessagePortChannel>);
+ virtual void postMessageToWorkerContext(PassRefPtr<SerializedScriptValue>, PassOwnPtr<MessagePortChannelArray>);
virtual bool hasPendingActivity() const;
virtual void workerObjectDestroyed();
// Implementations of WorkerObjectProxy.
// (Only use these methods in the worker context thread.)
- virtual void postMessageToWorkerObject(const String&, PassOwnPtr<MessagePortChannel>);
+ virtual void postMessageToWorkerObject(PassRefPtr<SerializedScriptValue>, PassOwnPtr<MessagePortChannelArray>);
virtual void postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL);
virtual void postConsoleMessageToWorkerObject(MessageDestination, MessageSource, MessageType, MessageLevel, const String& message, int lineNumber, const String& sourceURL);
virtual void confirmMessageFromWorkerObject(bool hasPendingActivity);
virtual void reportPendingActivity(bool hasPendingActivity);
+ virtual void workerContextClosed();
virtual void workerContextDestroyed();
// Implementation of WorkerLoaderProxy.
diff --git a/WebCore/workers/WorkerObjectProxy.h b/WebCore/workers/WorkerObjectProxy.h
index c5f4456..33e0bc3 100644
--- a/WebCore/workers/WorkerObjectProxy.h
+++ b/WebCore/workers/WorkerObjectProxy.h
@@ -33,31 +33,24 @@
#if ENABLE(WORKERS)
-#include "Console.h"
-
+#include "WorkerReportingProxy.h"
+#include "MessagePort.h"
#include <wtf/PassOwnPtr.h>
namespace WebCore {
class MessagePortChannel;
- class String;
// A proxy to talk to the worker object.
- class WorkerObjectProxy {
+ class WorkerObjectProxy : public WorkerReportingProxy {
public:
- virtual ~WorkerObjectProxy() {}
-
- virtual void postMessageToWorkerObject(const String&, PassOwnPtr<MessagePortChannel>) = 0;
-
- virtual void postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL) = 0;
-
- virtual void postConsoleMessageToWorkerObject(MessageDestination, MessageSource, MessageType, MessageLevel, const String& message, int lineNumber, const String& sourceURL) = 0;
+ virtual void postMessageToWorkerObject(PassRefPtr<SerializedScriptValue>, PassOwnPtr<MessagePortChannelArray>) = 0;
virtual void confirmMessageFromWorkerObject(bool hasPendingActivity) = 0;
-
virtual void reportPendingActivity(bool hasPendingActivity) = 0;
- virtual void workerContextDestroyed() = 0;
+ // No need to notify the parent page context when dedicated workers are closing.
+ virtual void workerContextClosed() { }
};
} // namespace WebCore
diff --git a/WebCore/workers/WorkerReportingProxy.h b/WebCore/workers/WorkerReportingProxy.h
new file mode 100644
index 0000000..f0447c8
--- /dev/null
+++ b/WebCore/workers/WorkerReportingProxy.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WorkerReportingProxy_h
+#define WorkerReportingProxy_h
+
+#if ENABLE(WORKERS)
+
+#include "Console.h"
+
+namespace WebCore {
+
+ class String;
+
+ // APIs used by workers to report console activity.
+ class WorkerReportingProxy {
+ public:
+ virtual ~WorkerReportingProxy() {}
+
+ virtual void postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL) = 0;
+
+ virtual void postConsoleMessageToWorkerObject(MessageDestination, MessageSource, MessageType, MessageLevel, const String& message, int lineNumber, const String& sourceURL) = 0;
+
+ // Invoked when close() is invoked on the worker context.
+ virtual void workerContextClosed() = 0;
+
+ // Invoked when the thread has stopped.
+ virtual void workerContextDestroyed() = 0;
+ };
+} // namespace WebCore
+
+#endif // ENABLE(WORKERS)
+
+#endif // WorkerReportingProxy_h
diff --git a/WebCore/workers/WorkerRunLoop.cpp b/WebCore/workers/WorkerRunLoop.cpp
index cb31fe7..39b21c6 100644
--- a/WebCore/workers/WorkerRunLoop.cpp
+++ b/WebCore/workers/WorkerRunLoop.cpp
@@ -77,7 +77,7 @@ public:
private:
Task(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode)
: m_task(task)
- , m_mode(mode.copy())
+ , m_mode(mode.crossThreadString())
{
}
@@ -173,6 +173,10 @@ MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerContext* context, const Mo
RefPtr<Task> task;
MessageQueueWaitResult result = m_messageQueue.waitForMessageFilteredWithTimeout(task, predicate, absoluteTime);
+ // If the context is closing, don't dispatch any further tasks (per section 4.1.1 of the Web Workers spec).
+ if (context->isClosing())
+ return result;
+
switch (result) {
case MessageQueueTerminated:
break;
@@ -201,7 +205,7 @@ void WorkerRunLoop::postTask(PassRefPtr<ScriptExecutionContext::Task> task)
void WorkerRunLoop::postTaskForMode(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode)
{
- m_messageQueue.append(Task::create(task, mode.copy()));
+ m_messageQueue.append(Task::create(task, mode.crossThreadString()));
}
} // namespace WebCore
diff --git a/WebCore/workers/WorkerScriptLoader.cpp b/WebCore/workers/WorkerScriptLoader.cpp
index 0162b26..52baf2d 100644
--- a/WebCore/workers/WorkerScriptLoader.cpp
+++ b/WebCore/workers/WorkerScriptLoader.cpp
@@ -50,7 +50,7 @@ WorkerScriptLoader::WorkerScriptLoader()
{
}
-void WorkerScriptLoader::loadSynchronously(ScriptExecutionContext* scriptExecutionContext, const KURL& url, CrossOriginRedirectPolicy crossOriginRedirectPolicy)
+void WorkerScriptLoader::loadSynchronously(ScriptExecutionContext* scriptExecutionContext, const KURL& url, CrossOriginRequestPolicy crossOriginRequestPolicy)
{
m_url = url;
@@ -59,10 +59,15 @@ void WorkerScriptLoader::loadSynchronously(ScriptExecutionContext* scriptExecuti
return;
ASSERT(scriptExecutionContext->isWorkerContext());
- WorkerThreadableLoader::loadResourceSynchronously(static_cast<WorkerContext*>(scriptExecutionContext), *request, *this, AllowStoredCredentials, crossOriginRedirectPolicy);
+
+ ThreadableLoaderOptions options;
+ options.allowCredentials = true;
+ options.crossOriginRequestPolicy = crossOriginRequestPolicy;
+
+ WorkerThreadableLoader::loadResourceSynchronously(static_cast<WorkerContext*>(scriptExecutionContext), *request, *this, options);
}
-void WorkerScriptLoader::loadAsynchronously(ScriptExecutionContext* scriptExecutionContext, const KURL& url, CrossOriginRedirectPolicy crossOriginRedirectPolicy, WorkerScriptLoaderClient* client)
+void WorkerScriptLoader::loadAsynchronously(ScriptExecutionContext* scriptExecutionContext, const KURL& url, CrossOriginRequestPolicy crossOriginRequestPolicy, WorkerScriptLoaderClient* client)
{
ASSERT(client);
m_client = client;
@@ -72,7 +77,11 @@ void WorkerScriptLoader::loadAsynchronously(ScriptExecutionContext* scriptExecut
if (!request)
return;
- m_threadableLoader = ThreadableLoader::create(scriptExecutionContext, this, *request, DoNotSendLoadCallbacks, DoNotSniffContent, AllowStoredCredentials, crossOriginRedirectPolicy);
+ ThreadableLoaderOptions options;
+ options.allowCredentials = true;
+ options.crossOriginRequestPolicy = crossOriginRequestPolicy;
+
+ m_threadableLoader = ThreadableLoader::create(scriptExecutionContext, this, *request, options);
}
PassOwnPtr<ResourceRequest> WorkerScriptLoader::createResourceRequest()
diff --git a/WebCore/workers/WorkerScriptLoader.h b/WebCore/workers/WorkerScriptLoader.h
index 2924ec8..47623f6 100644
--- a/WebCore/workers/WorkerScriptLoader.h
+++ b/WebCore/workers/WorkerScriptLoader.h
@@ -46,8 +46,8 @@ namespace WebCore {
public:
WorkerScriptLoader();
- void loadSynchronously(ScriptExecutionContext*, const KURL&, CrossOriginRedirectPolicy);
- void loadAsynchronously(ScriptExecutionContext*, const KURL&, CrossOriginRedirectPolicy, WorkerScriptLoaderClient*);
+ void loadSynchronously(ScriptExecutionContext*, const KURL&, CrossOriginRequestPolicy);
+ void loadAsynchronously(ScriptExecutionContext*, const KURL&, CrossOriginRequestPolicy, WorkerScriptLoaderClient*);
void notifyError();
diff --git a/WebCore/workers/WorkerThread.cpp b/WebCore/workers/WorkerThread.cpp
index 86a5fa8..467157b 100644
--- a/WebCore/workers/WorkerThread.cpp
+++ b/WebCore/workers/WorkerThread.cpp
@@ -40,6 +40,21 @@
#include <wtf/Noncopyable.h>
namespace WebCore {
+
+static Mutex& threadCountMutex()
+{
+ AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
+ return mutex;
+}
+
+unsigned WorkerThread::m_threadCount = 0;
+
+unsigned WorkerThread::workerThreadCount()
+{
+ MutexLocker lock(threadCountMutex());
+ return m_threadCount;
+}
+
struct WorkerThreadStartupData : Noncopyable {
public:
static std::auto_ptr<WorkerThreadStartupData> create(const KURL& scriptURL, const String& userAgent, const String& sourceCode)
@@ -56,20 +71,26 @@ private:
WorkerThreadStartupData::WorkerThreadStartupData(const KURL& scriptURL, const String& userAgent, const String& sourceCode)
: m_scriptURL(scriptURL.copy())
- , m_userAgent(userAgent.copy())
- , m_sourceCode(sourceCode.copy())
+ , m_userAgent(userAgent.crossThreadString())
+ , m_sourceCode(sourceCode.crossThreadString())
{
}
-WorkerThread::WorkerThread(const KURL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy)
+WorkerThread::WorkerThread(const KURL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy)
: m_threadID(0)
, m_workerLoaderProxy(workerLoaderProxy)
+ , m_workerReportingProxy(workerReportingProxy)
, m_startupData(WorkerThreadStartupData::create(scriptURL, userAgent, sourceCode))
{
+ MutexLocker lock(threadCountMutex());
+ m_threadCount++;
}
WorkerThread::~WorkerThread()
{
+ MutexLocker lock(threadCountMutex());
+ ASSERT(m_threadCount > 0);
+ m_threadCount--;
}
bool WorkerThread::start()
diff --git a/WebCore/workers/WorkerThread.h b/WebCore/workers/WorkerThread.h
index a6b22dc..cb33308 100644
--- a/WebCore/workers/WorkerThread.h
+++ b/WebCore/workers/WorkerThread.h
@@ -37,9 +37,11 @@
namespace WebCore {
class KURL;
+ class NotificationPresenter;
class String;
class WorkerContext;
class WorkerLoaderProxy;
+ class WorkerReportingProxy;
struct WorkerThreadStartupData;
class WorkerThread : public RefCounted<WorkerThread> {
@@ -52,9 +54,18 @@ namespace WebCore {
ThreadIdentifier threadID() const { return m_threadID; }
WorkerRunLoop& runLoop() { return m_runLoop; }
WorkerLoaderProxy& workerLoaderProxy() const { return m_workerLoaderProxy; }
+ WorkerReportingProxy& workerReportingProxy() const { return m_workerReportingProxy; }
+
+ // Number of active worker threads.
+ static unsigned workerThreadCount();
+
+#if ENABLE(NOTIFICATIONS)
+ NotificationPresenter* getNotificationPresenter() { return m_notificationPresenter; }
+ void setNotificationPresenter(NotificationPresenter* presenter) { m_notificationPresenter = presenter; }
+#endif
protected:
- WorkerThread(const KURL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&);
+ WorkerThread(const KURL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerReportingProxy&);
// Factory method for creating a new worker context for the thread.
virtual PassRefPtr<WorkerContext> createWorkerContext(const KURL& url, const String& userAgent) = 0;
@@ -72,11 +83,19 @@ namespace WebCore {
ThreadIdentifier m_threadID;
WorkerRunLoop m_runLoop;
WorkerLoaderProxy& m_workerLoaderProxy;
+ WorkerReportingProxy& m_workerReportingProxy;
RefPtr<WorkerContext> m_workerContext;
Mutex m_threadCreationMutex;
OwnPtr<WorkerThreadStartupData> m_startupData;
+
+#if ENABLE(NOTIFICATIONS)
+ NotificationPresenter* m_notificationPresenter;
+#endif
+
+ // Track the number of WorkerThread instances for use in layout tests.
+ static unsigned m_threadCount;
};
} // namespace WebCore