diff options
Diffstat (limited to 'WebCore/workers')
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 |