diff options
author | atwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-05 22:37:42 +0000 |
---|---|---|
committer | atwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-05 22:37:42 +0000 |
commit | 9c00f00af8403072573aa4b80c51a055162683f6 (patch) | |
tree | c228a1e6b99deb72d04d36e63d0a21d35bd35323 /webkit | |
parent | 89f008927b90c6d8997416e766e7340c158093c3 (diff) | |
download | chromium_src-9c00f00af8403072573aa4b80c51a055162683f6.zip chromium_src-9c00f00af8403072573aa4b80c51a055162683f6.tar.gz chromium_src-9c00f00af8403072573aa4b80c51a055162683f6.tar.bz2 |
Initial WebSharedWorkerImpl implementation
Refactored WebWorkerImpl into WebWorkerBase to enable code sharing with
WebSharedWorkerImpl.
Changed how SharedWorkers are instantiated (now routed through WebFrameClient
just like DedicatedWorkers, because WebFrameClient is the only one who knows
how to send messages to RenderViewHost.
BUG=26233
TEST=none (will enable layout tests when basic functionality available)
Review URL: http://codereview.chromium.org/362020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31151 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/api/WebKit.gyp | 2 | ||||
-rw-r--r-- | webkit/api/public/WebCommonWorkerClient.h | 1 | ||||
-rw-r--r-- | webkit/api/public/WebFrameClient.h | 4 | ||||
-rw-r--r-- | webkit/api/public/WebSharedWorker.h | 5 | ||||
-rw-r--r-- | webkit/api/public/WebSharedWorkerRepository.h | 5 | ||||
-rw-r--r-- | webkit/api/src/SharedWorkerRepository.cpp | 15 | ||||
-rw-r--r-- | webkit/api/src/WebSharedWorkerImpl.cpp | 82 | ||||
-rw-r--r-- | webkit/api/src/WebSharedWorkerImpl.h | 21 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerBase.cpp | 307 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerBase.h | 149 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerClientImpl.cpp | 12 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerClientImpl.h | 1 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerImpl.cpp | 244 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerImpl.h | 80 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_web_worker.h | 1 |
15 files changed, 594 insertions, 335 deletions
diff --git a/webkit/api/WebKit.gyp b/webkit/api/WebKit.gyp index dbce149..0c8d4ca 100644 --- a/webkit/api/WebKit.gyp +++ b/webkit/api/WebKit.gyp @@ -282,6 +282,8 @@ 'src/WebURLError.cpp', 'src/WebViewImpl.cpp', 'src/WebViewImpl.h', + 'src/WebWorkerBase.cpp', + 'src/WebWorkerBase.h', 'src/WebWorkerClientImpl.cpp', 'src/WebWorkerClientImpl.h', 'src/WebWorkerImpl.cpp', diff --git a/webkit/api/public/WebCommonWorkerClient.h b/webkit/api/public/WebCommonWorkerClient.h index fd7e399..0726a43 100644 --- a/webkit/api/public/WebCommonWorkerClient.h +++ b/webkit/api/public/WebCommonWorkerClient.h @@ -57,6 +57,7 @@ namespace WebKit { int lineNumber, const WebString& sourceURL) = 0; + virtual void workerContextClosed() = 0; virtual void workerContextDestroyed() = 0; // Returns the notification presenter for this worker context. Pointer diff --git a/webkit/api/public/WebFrameClient.h b/webkit/api/public/WebFrameClient.h index a592c21..804f7b7 100644 --- a/webkit/api/public/WebFrameClient.h +++ b/webkit/api/public/WebFrameClient.h @@ -45,6 +45,7 @@ namespace WebKit { class WebNode; class WebPlugin; class WebSecurityOrigin; + class WebSharedWorker; class WebString; class WebURL; class WebURLRequest; @@ -67,6 +68,9 @@ namespace WebKit { virtual WebWorker* createWorker(WebFrame*, WebWorkerClient*) { return 0; } // May return null. + virtual WebSharedWorker* createSharedWorker(WebFrame*, const WebURL&, const WebString&, unsigned long long) { return 0; } + + // May return null. virtual WebMediaPlayer* createMediaPlayer(WebFrame*, WebMediaPlayerClient*) { return 0; } diff --git a/webkit/api/public/WebSharedWorker.h b/webkit/api/public/WebSharedWorker.h index a580882..5bdf6ae 100644 --- a/webkit/api/public/WebSharedWorker.h +++ b/webkit/api/public/WebSharedWorker.h @@ -33,8 +33,11 @@ #include "WebCommon.h" -namespace WebKit { +namespace WebCore { class ScriptExecutionContext; +} + +namespace WebKit { class WebString; class WebMessagePortChannel; class WebCommonWorkerClient; diff --git a/webkit/api/public/WebSharedWorkerRepository.h b/webkit/api/public/WebSharedWorkerRepository.h index b37b47a..508917c 100644 --- a/webkit/api/public/WebSharedWorkerRepository.h +++ b/webkit/api/public/WebSharedWorkerRepository.h @@ -43,9 +43,8 @@ namespace WebKit { // Unique identifier for the parent document of a worker (unique within a given process). typedef unsigned long long DocumentID; - // Connects the passed SharedWorker object with the specified worker thread. - // Caller is responsible for freeing the returned object. Returns null if a SharedWorker with that name already exists but with a different URL. - virtual WebSharedWorker* lookup(const WebURL&, const WebString&, DocumentID) = 0; + // Tracks a newly-created SharedWorker via the repository. + virtual void addSharedWorker(WebSharedWorker*, DocumentID) = 0; // Invoked when a document has been detached. DocumentID can be re-used after documentDetached() is invoked. virtual void documentDetached(DocumentID) = 0; diff --git a/webkit/api/src/SharedWorkerRepository.cpp b/webkit/api/src/SharedWorkerRepository.cpp index 32e8fd7..194e75a 100644 --- a/webkit/api/src/SharedWorkerRepository.cpp +++ b/webkit/api/src/SharedWorkerRepository.cpp @@ -40,6 +40,8 @@ #include "PlatformMessagePortChannel.h" #include "ScriptExecutionContext.h" #include "SharedWorker.h" +#include "WebFrameClient.h" +#include "WebFrameImpl.h" #include "WebKit.h" #include "WebKitClient.h" #include "WebMessagePortChannel.h" @@ -53,6 +55,7 @@ namespace WebCore { class Document; +using WebKit::WebFrameImpl;; using WebKit::WebMessagePortChannel; using WebKit::WebSharedWorker; using WebKit::WebSharedWorkerRepository; @@ -127,12 +130,16 @@ static WebSharedWorkerRepository::DocumentID getId(void* document) void SharedWorkerRepository::connect(PassRefPtr<SharedWorker> worker, PassOwnPtr<MessagePortChannel> port, const KURL& url, const String& name, ExceptionCode& ec) { - ScriptExecutionContext* context = worker->scriptExecutionContext(); + // This should not be callable unless there's a SharedWorkerRepository for + // this context (since isAvailable() should have returned null). + ASSERT(WebKit::webKitClient()->sharedWorkerRepository()); + // No nested workers (for now) - connect() should only be called from document context. - ASSERT(context->isDocument()); + ASSERT(worker->scriptExecutionContext()->isDocument()); + Document* document = static_cast<Document*>(worker->scriptExecutionContext()); + WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame()); OwnPtr<WebSharedWorker> webWorker; - ASSERT(WebKit::webKitClient()->sharedWorkerRepository()); - webWorker = WebKit::webKitClient()->sharedWorkerRepository()->lookup(url, name, getId(context)); + webWorker = webFrame->client()->createSharedWorker(webFrame, url, name, getId(document)); if (!webWorker) { // Existing worker does not match this url, so return an error back to the caller. diff --git a/webkit/api/src/WebSharedWorkerImpl.cpp b/webkit/api/src/WebSharedWorkerImpl.cpp index e5c9fc5..af76c2a 100644 --- a/webkit/api/src/WebSharedWorkerImpl.cpp +++ b/webkit/api/src/WebSharedWorkerImpl.cpp @@ -31,17 +31,93 @@ #include "config.h" #include "WebSharedWorkerImpl.h" +#include "GenericWorkerTask.h" +#include "KURL.h" +#include "MessageEvent.h" +#include "MessagePortChannel.h" +#include "PlatformMessagePortChannel.h" +#include "ScriptExecutionContext.h" +#include "SharedWorkerContext.h" +#include "SharedWorkerThread.h" + +#include "WebMessagePortChannel.h" +#include "WebString.h" +#include "WebURL.h" + using namespace WebCore; namespace WebKit { #if ENABLE(SHARED_WORKERS) -WebSharedWorker* WebSharedWorker::create(WebCommonWorkerClient* client) +WebSharedWorkerImpl::WebSharedWorkerImpl(WebCommonWorkerClient* client) + : m_client(client) +{ +} + +WebSharedWorkerImpl::~WebSharedWorkerImpl() +{ +} + +bool WebSharedWorkerImpl::isStarted() { - // FIXME: Return an instance of WebSharedWorkerImpl once the implementation is complete. + // Should not ever be called from the worker thread (this API is only called on WebSharedWorkerProxy on the renderer thread). ASSERT_NOT_REACHED(); - return NULL; + return workerThread(); +} + +void WebSharedWorkerImpl::connect(WebMessagePortChannel* webChannel) +{ + // Convert the WebMessagePortChanel to a WebCore::MessagePortChannel. + RefPtr<PlatformMessagePortChannel> platform_channel = + PlatformMessagePortChannel::create(webChannel); + webChannel->setClient(platform_channel.get()); + OwnPtr<MessagePortChannel> channel = + MessagePortChannel::create(platform_channel); + + workerThread()->runLoop().postTask( + createCallbackTask(&connectTask, this, channel.release())); +} + +void WebSharedWorkerImpl::connectTask(ScriptExecutionContext* context, WebSharedWorkerImpl* worker, PassOwnPtr<MessagePortChannel> channel) +{ + // Wrap the passed-in channel in a MessagePort, and send it off via a connect event. + RefPtr<MessagePort> port = MessagePort::create(*context); + port->entangle(channel.release()); + ASSERT(context->isWorkerContext()); + WorkerContext* workerContext = static_cast<WorkerContext*>(context); + ASSERT(workerContext->isSharedWorkerContext()); + workerContext->toSharedWorkerContext()->dispatchEvent(createConnectEvent(port)); +} + +void WebSharedWorkerImpl::startWorkerContext(const WebURL& url, const WebString& name, const WebString& userAgent, const WebString& sourceCode) +{ + initializeLoader(url); + setWorkerThread(SharedWorkerThread::create(name, url, userAgent, sourceCode, *this, *this)); + workerThread()->start(); +} + +void WebSharedWorkerImpl::terminateWorkerContext() +{ + stopWorkerThread(); +} + +void WebSharedWorkerImpl::clientDestroyed() +{ + m_client = 0; +} + +WebWorkerClient* WebSharedWorkerImpl::client() +{ + // We should never be asked for a WebWorkerClient (only dedicated workers have an associated WebWorkerClient). + // It should not be possible for SharedWorkerContext to generate an API call outside those supported by WebCommonWorkerClient. + ASSERT_NOT_REACHED(); + return 0; +} + +WebSharedWorker* WebSharedWorker::create(WebCommonWorkerClient* client) +{ + return new WebSharedWorkerImpl(client); } #endif // ENABLE(SHARED_WORKERS) diff --git a/webkit/api/src/WebSharedWorkerImpl.h b/webkit/api/src/WebSharedWorkerImpl.h index fad0f5a..7d38dbe 100644 --- a/webkit/api/src/WebSharedWorkerImpl.h +++ b/webkit/api/src/WebSharedWorkerImpl.h @@ -36,23 +36,16 @@ #if ENABLE(SHARED_WORKERS) #include "ScriptExecutionContext.h" -#include "WorkerLoaderProxy.h" -#include "WorkerObjectProxy.h" -#include <wtf/PassOwnPtr.h> -#include <wtf/RefPtr.h> -namespace WebCore { -class SharedWorkerThread; -} +#include "WebWorkerBase.h" namespace WebKit { -class WebView; // This class is used by the worker process code to talk to the WebCore::SharedWorker implementation. // It can't use it directly since it uses WebKit types, so this class converts the data types. // When the WebCore::SharedWorker object wants to call WebCore::WorkerReportingProxy, this class will // convert to Chrome data types first and then call the supplied WebCommonWorkerClient. -class WebSharedWorkerImpl : public WebCore::WorkerLoaderProxy { +class WebSharedWorkerImpl : public WebWorkerBase, public WebSharedWorker { public: explicit WebSharedWorkerImpl(WebCommonWorkerClient* client); @@ -60,15 +53,19 @@ public: virtual bool isStarted(); virtual void startWorkerContext(const WebURL&, const WebString& name, const WebString& userAgent, const WebString& sourceCode); virtual void connect(WebMessagePortChannel*); + virtual void terminateWorkerContext(); + virtual void clientDestroyed(); - WebCommonWorkerClient* client() { return m_client; } + // WebWorkerBase methods: + WebWorkerClient* client(); + WebCommonWorkerClient* commonClient() { return m_client; } private: virtual ~WebSharedWorkerImpl(); - WebCommonWorkerClient* m_client; + static void connectTask(WebCore::ScriptExecutionContext*, WebSharedWorkerImpl*, PassOwnPtr<WebCore::MessagePortChannel>); - RefPtr<WebCore::SharedWorkerThread> m_workerThread; + WebCommonWorkerClient* m_client; }; } // namespace WebKit diff --git a/webkit/api/src/WebWorkerBase.cpp b/webkit/api/src/WebWorkerBase.cpp new file mode 100644 index 0000000..3f19c4b --- /dev/null +++ b/webkit/api/src/WebWorkerBase.cpp @@ -0,0 +1,307 @@ +/* + * 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. + */ + +#include "config.h" +#include "WebWorkerBase.h" + +#include "GenericWorkerTask.h" +#include "MessagePortChannel.h" +#include "WorkerThread.h" +#include <wtf/MainThread.h> + +#include "PlatformMessagePortChannel.h" +#include "WebDataSourceImpl.h" +#include "WebFrameClient.h" +#include "WebFrameImpl.h" +#include "WebMessagePortChannel.h" +#include "WebWorkerClient.h" +#include "WebView.h" + +using namespace WebCore; + +namespace WebKit { + +#if ENABLE(WORKERS) + +// Dummy WebViewDelegate - we only need it in Worker process to load a +// 'shadow page' which will initialize WebCore loader. +class WorkerWebFrameClient : public WebFrameClient { +public: + // Tell the loader to load the data into the 'shadow page' synchronously, + // so we can grab the resulting Document right after load. + virtual void didCreateDataSource(WebFrame* frame, WebDataSource* ds) + { + static_cast<WebDataSourceImpl*>(ds)->setDeferMainResourceDataLoad(false); + } + + // Lazy allocate and leak this instance. + static WorkerWebFrameClient* sharedInstance() + { + static WorkerWebFrameClient client; + return &client; + } + +private: + WorkerWebFrameClient() + { + } +}; + +// This function is called on the main thread to force to initialize some static +// values used in WebKit before any worker thread is started. This is because in +// our worker processs, we do not run any WebKit code in main thread and thus +// when multiple workers try to start at the same time, we might hit crash due +// to contention for initializing static values. +static void initializeWebKitStaticValues() +{ + static bool initialized = false; + if (!initialized) { + initialized = true; + // Note that we have to pass a URL with valid protocol in order to follow + // the path to do static value initializations. + RefPtr<SecurityOrigin> origin = + SecurityOrigin::create(KURL(ParsedURLString, "http://localhost")); + origin.release(); + } +} + +WebWorkerBase::WebWorkerBase() + : m_webView(0) + , m_askedToTerminate(false) +{ + initializeWebKitStaticValues(); +} + +WebWorkerBase::~WebWorkerBase() +{ + ASSERT(m_webView); + m_webView->close(); +} + +void WebWorkerBase::stopWorkerThread() +{ + if (m_askedToTerminate) + return; + m_askedToTerminate = true; + if (m_workerThread) + m_workerThread->stop(); +} + +void WebWorkerBase::initializeLoader(const WebURL& url) +{ + // Create 'shadow page'. This page is never displayed, it is used to proxy the + // loading requests from the worker context to the rest of WebKit and Chromium + // infrastructure. + ASSERT(!m_webView); + m_webView = WebView::create(0); + m_webView->initializeMainFrame(WorkerWebFrameClient::sharedInstance()); + + WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame()); + + // Construct substitute data source for the 'shadow page'. We only need it + // to have same origin as the worker so the loading checks work correctly. + CString content(""); + int len = static_cast<int>(content.length()); + RefPtr<SharedBuffer> buf(SharedBuffer::create(content.data(), len)); + SubstituteData substData(buf, String("text/html"), String("UTF-8"), KURL()); + ResourceRequest request(url, CString()); + webFrame->frame()->loader()->load(request, substData, false); + + // This document will be used as 'loading context' for the worker. + m_loadingDocument = webFrame->frame()->document(); +} + +void WebWorkerBase::dispatchTaskToMainThread(PassOwnPtr<ScriptExecutionContext::Task> task) +{ + return callOnMainThread(invokeTaskMethod, task.release()); +} + +void WebWorkerBase::invokeTaskMethod(void* param) +{ + ScriptExecutionContext::Task* task = + static_cast<ScriptExecutionContext::Task*>(param); + task->performTask(0); + delete task; +} + +// WorkerObjectProxy ----------------------------------------------------------- + +void WebWorkerBase::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> message, + PassOwnPtr<MessagePortChannelArray> channels) +{ + dispatchTaskToMainThread(createCallbackTask(&postMessageTask, this, + message->toString(), channels)); +} + +void WebWorkerBase::postMessageTask(ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + String message, + PassOwnPtr<MessagePortChannelArray> channels) +{ + if (!thisPtr->client()) + return; + + WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0); + for (size_t i = 0; i < webChannels.size(); ++i) { + webChannels[i] = (*channels)[i]->channel()->webChannelRelease(); + webChannels[i]->setClient(0); + } + + thisPtr->client()->postMessageToWorkerObject(message, webChannels); +} + +void WebWorkerBase::postExceptionToWorkerObject(const String& errorMessage, + int lineNumber, + const String& sourceURL) +{ + dispatchTaskToMainThread(createCallbackTask(&postExceptionTask, this, + errorMessage, lineNumber, + sourceURL)); +} + +void WebWorkerBase::postExceptionTask(ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + const String& errorMessage, + int lineNumber, const String& sourceURL) +{ + if (!thisPtr->commonClient()) + return; + + thisPtr->commonClient()->postExceptionToWorkerObject(errorMessage, + lineNumber, + sourceURL); +} + +void WebWorkerBase::postConsoleMessageToWorkerObject(MessageDestination destination, + MessageSource source, + MessageType type, + MessageLevel level, + const String& message, + int lineNumber, + const String& sourceURL) +{ + dispatchTaskToMainThread(createCallbackTask(&postConsoleMessageTask, this, + static_cast<int>(destination), + static_cast<int>(source), + static_cast<int>(type), + static_cast<int>(level), + message, lineNumber, sourceURL)); +} + +void WebWorkerBase::postConsoleMessageTask(ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + int destination, int source, + int type, int level, + const String& message, + int lineNumber, + const String& sourceURL) +{ + if (!thisPtr->commonClient()) + return; + thisPtr->commonClient()->postConsoleMessageToWorkerObject(destination, source, + type, level, message, + lineNumber, sourceURL); +} + +void WebWorkerBase::confirmMessageFromWorkerObject(bool hasPendingActivity) +{ + dispatchTaskToMainThread(createCallbackTask(&confirmMessageTask, this, + hasPendingActivity)); +} + +void WebWorkerBase::confirmMessageTask(ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + bool hasPendingActivity) +{ + if (!thisPtr->client()) + return; + thisPtr->client()->confirmMessageFromWorkerObject(hasPendingActivity); +} + +void WebWorkerBase::reportPendingActivity(bool hasPendingActivity) +{ + dispatchTaskToMainThread(createCallbackTask(&reportPendingActivityTask, + this, hasPendingActivity)); +} + +void WebWorkerBase::reportPendingActivityTask(ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + bool hasPendingActivity) +{ + if (!thisPtr->client()) + return; + thisPtr->client()->reportPendingActivity(hasPendingActivity); +} + +void WebWorkerBase::workerContextClosed() +{ + dispatchTaskToMainThread(createCallbackTask(&workerContextClosedTask, + this)); +} + +void WebWorkerBase::workerContextClosedTask(ScriptExecutionContext* context, + WebWorkerBase* thisPtr) +{ + if (thisPtr->commonClient()) + thisPtr->commonClient()->workerContextClosed(); +} + +void WebWorkerBase::workerContextDestroyed() +{ + dispatchTaskToMainThread(createCallbackTask(&workerContextDestroyedTask, + this)); +} + +void WebWorkerBase::workerContextDestroyedTask(ScriptExecutionContext* context, + WebWorkerBase* thisPtr) +{ + if (thisPtr->commonClient()) + thisPtr->commonClient()->workerContextDestroyed(); + // The lifetime of this proxy is controlled by the worker context. + delete thisPtr; +} + +// WorkerLoaderProxy ----------------------------------------------------------- + +void WebWorkerBase::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task> task) +{ + ASSERT(m_loadingDocument->isDocument()); + m_loadingDocument->postTask(task); +} + +void WebWorkerBase::postTaskForModeToWorkerContext( + PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode) +{ + m_workerThread->runLoop().postTaskForMode(task, mode); +} + +#endif // ENABLE(WORKERS) + +} // namespace WebKit diff --git a/webkit/api/src/WebWorkerBase.h b/webkit/api/src/WebWorkerBase.h new file mode 100644 index 0000000..0217401 --- /dev/null +++ b/webkit/api/src/WebWorkerBase.h @@ -0,0 +1,149 @@ +/* + * 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 WebWorkerBase_h +#define WebWorkerBase_h + +#if ENABLE(WORKERS) + +#include "ScriptExecutionContext.h" +#include "WorkerLoaderProxy.h" +#include "WorkerObjectProxy.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { +class WorkerThread; +} + +namespace WebKit { +class WebCommonWorkerClient; +class WebURL; +class WebView; +class WebWorkerClient; + +// Base class for WebSharedWorkerImpl and WebWorkerImpl. It contains common +// code used by both implementation classes, including implementations of the +// WorkerObjectProxy and WorkerLoaderProxy interfaces. +class WebWorkerBase : public WebCore::WorkerObjectProxy + , public WebCore::WorkerLoaderProxy { +public: + WebWorkerBase(); + virtual ~WebWorkerBase(); + + // WebCore::WorkerObjectProxy methods: + virtual void postMessageToWorkerObject( + PassRefPtr<WebCore::SerializedScriptValue>, + PassOwnPtr<WebCore::MessagePortChannelArray>); + virtual void postExceptionToWorkerObject( + const WebCore::String&, int, const WebCore::String&); + virtual void postConsoleMessageToWorkerObject( + WebCore::MessageDestination, WebCore::MessageSource, WebCore::MessageType, + WebCore::MessageLevel, const WebCore::String&, int, const WebCore::String&); + virtual void confirmMessageFromWorkerObject(bool); + virtual void reportPendingActivity(bool); + virtual void workerContextClosed(); + virtual void workerContextDestroyed(); + + // WebCore::WorkerLoaderProxy methods: + virtual void postTaskToLoader(PassOwnPtr<WebCore::ScriptExecutionContext::Task>); + virtual void postTaskForModeToWorkerContext( + PassOwnPtr<WebCore::ScriptExecutionContext::Task>, const WebCore::String& mode); + + // Executes the given task on the main thread. + static void dispatchTaskToMainThread(PassOwnPtr<WebCore::ScriptExecutionContext::Task>); + +protected: + virtual WebWorkerClient* client() = 0; + virtual WebCommonWorkerClient* commonClient() = 0; + + void setWorkerThread(PassRefPtr<WebCore::WorkerThread> thread) { m_workerThread = thread; } + WebCore::WorkerThread* workerThread() { return m_workerThread.get(); } + + // Shuts down the worker thread. + void stopWorkerThread(); + + // Creates the shadow loader used for worker network requests. + void initializeLoader(const WebURL&); + +private: + // Function used to invoke tasks on the main thread. + static void invokeTaskMethod(void*); + + // Tasks that are run on the main thread. + static void postMessageTask( + WebCore::ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + WebCore::String message, + PassOwnPtr<WebCore::MessagePortChannelArray> channels); + static void postExceptionTask( + WebCore::ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + const WebCore::String& message, + int lineNumber, + const WebCore::String& sourceURL); + static void postConsoleMessageTask( + WebCore::ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + int destination, + int source, + int type, + int level, + const WebCore::String& message, + int lineNumber, + const WebCore::String& sourceURL); + static void confirmMessageTask( + WebCore::ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + bool hasPendingActivity); + static void reportPendingActivityTask( + WebCore::ScriptExecutionContext* context, + WebWorkerBase* thisPtr, + bool hasPendingActivity); + static void workerContextClosedTask( + WebCore::ScriptExecutionContext* context, + WebWorkerBase* thisPtr); + static void workerContextDestroyedTask( + WebCore::ScriptExecutionContext* context, + WebWorkerBase* thisPtr); + + // 'shadow page' - created to proxy loading requests from the worker. + RefPtr<WebCore::ScriptExecutionContext> m_loadingDocument; + WebView* m_webView; + bool m_askedToTerminate; + + RefPtr<WebCore::WorkerThread> m_workerThread; +}; + +} // namespace WebKit + +#endif // ENABLE(WORKERS) + +#endif diff --git a/webkit/api/src/WebWorkerClientImpl.cpp b/webkit/api/src/WebWorkerClientImpl.cpp index 5e99b57..6be03a7 100644 --- a/webkit/api/src/WebWorkerClientImpl.cpp +++ b/webkit/api/src/WebWorkerClientImpl.cpp @@ -139,7 +139,7 @@ void WebWorkerClientImpl::startWorkerContext(const KURL& scriptURL, if (m_askedToTerminate) return; if (!isMainThread()) { - WebWorkerImpl::dispatchTaskToMainThread(createCallbackTask( + WebWorkerBase::dispatchTaskToMainThread(createCallbackTask( &startWorkerContextTask, this, scriptURL.string(), @@ -156,7 +156,7 @@ void WebWorkerClientImpl::terminateWorkerContext() return; m_askedToTerminate = true; if (!isMainThread()) { - WebWorkerImpl::dispatchTaskToMainThread(createCallbackTask(&terminateWorkerContextTask, this)); + WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&terminateWorkerContextTask, this)); return; } m_webWorker->terminateWorkerContext(); @@ -171,7 +171,7 @@ void WebWorkerClientImpl::postMessageToWorkerContext( return; ++m_unconfirmedMessageCount; if (!isMainThread()) { - WebWorkerImpl::dispatchTaskToMainThread(createCallbackTask(&postMessageToWorkerContextTask, + WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&postMessageToWorkerContextTask, this, message->toString(), channels)); @@ -201,7 +201,7 @@ void WebWorkerClientImpl::workerObjectDestroyed() } // Even if this is called on the main thread, there could be a queued task for // this object, so don't delete it right away. - WebWorkerImpl::dispatchTaskToMainThread(createCallbackTask(&workerObjectDestroyedTask, + WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&workerObjectDestroyedTask, this)); } @@ -302,6 +302,10 @@ void WebWorkerClientImpl::workerContextDestroyed() { } +void WebWorkerClientImpl::workerContextClosed() +{ +} + void WebWorkerClientImpl::startWorkerContextTask(ScriptExecutionContext* context, WebWorkerClientImpl* thisPtr, const String& scriptURL, diff --git a/webkit/api/src/WebWorkerClientImpl.h b/webkit/api/src/WebWorkerClientImpl.h index fe59651..63acebc 100644 --- a/webkit/api/src/WebWorkerClientImpl.h +++ b/webkit/api/src/WebWorkerClientImpl.h @@ -82,6 +82,7 @@ public: int, const WebString&); virtual void confirmMessageFromWorkerObject(bool); virtual void reportPendingActivity(bool); + virtual void workerContextClosed(); virtual void workerContextDestroyed(); virtual WebWorker* createWorker(WebWorkerClient*) { return 0; } virtual WebNotificationPresenter* notificationPresenter() diff --git a/webkit/api/src/WebWorkerImpl.cpp b/webkit/api/src/WebWorkerImpl.cpp index 77eb73c..744be30 100644 --- a/webkit/api/src/WebWorkerImpl.cpp +++ b/webkit/api/src/WebWorkerImpl.cpp @@ -42,18 +42,12 @@ #include "SecurityOrigin.h" #include "SerializedScriptValue.h" #include "SubstituteData.h" -#include <wtf/MainThread.h> #include <wtf/Threading.h> #include "PlatformMessagePortChannel.h" -#include "WebDataSourceImpl.h" -#include "WebFrameClient.h" -#include "WebFrameImpl.h" #include "WebMessagePortChannel.h" -#include "WebScreenInfo.h" #include "WebString.h" #include "WebURL.h" -#include "WebView.h" #include "WebWorkerClient.h" using namespace WebCore; @@ -62,64 +56,24 @@ namespace WebKit { #if ENABLE(WORKERS) -// Dummy WebViewDelegate - we only need it in Worker process to load a -// 'shadow page' which will initialize WebCore loader. -class WorkerWebFrameClient : public WebKit::WebFrameClient { -public: - // Tell the loader to load the data into the 'shadow page' synchronously, - // so we can grab the resulting Document right after load. - virtual void didCreateDataSource(WebFrame* frame, WebDataSource* ds) - { - static_cast<WebDataSourceImpl*>(ds)->setDeferMainResourceDataLoad(false); - } - - // Lazy allocate and leak this instance. - static WorkerWebFrameClient* sharedInstance() - { - static WorkerWebFrameClient client; - return &client; - } - -private: - WorkerWebFrameClient() - { - } -}; - WebWorker* WebWorker::create(WebWorkerClient* client) { return new WebWorkerImpl(client); } -// This function is called on the main thread to force to initialize some static -// values used in WebKit before any worker thread is started. This is because in -// our worker processs, we do not run any WebKit code in main thread and thus -// when multiple workers try to start at the same time, we might hit crash due -// to contention for initializing static values. -void initializeWebKitStaticValues() -{ - static bool initialized = false; - if (!initialized) { - initialized = true; - // Note that we have to pass a URL with valid protocol in order to follow - // the path to do static value initializations. - RefPtr<SecurityOrigin> origin = - SecurityOrigin::create(KURL(ParsedURLString, "http://localhost")); - origin.release(); - } -} WebWorkerImpl::WebWorkerImpl(WebWorkerClient* client) : m_client(client) - , m_webView(0) - , m_askedToTerminate(false) { - initializeWebKitStaticValues(); } WebWorkerImpl::~WebWorkerImpl() { - m_webView->close(); +} + +WebCommonWorkerClient* WebWorkerImpl::commonClient() +{ + return m_client; } void WebWorkerImpl::postMessageToWorkerContextTask(WebCore::ScriptExecutionContext* context, @@ -146,41 +100,17 @@ void WebWorkerImpl::startWorkerContext(const WebURL& scriptUrl, const WebString& userAgent, const WebString& sourceCode) { - // Create 'shadow page'. This page is never displayed, it is used to proxy the - // loading requests from the worker context to the rest of WebKit and Chromium - // infrastructure. - ASSERT(!m_webView); - m_webView = WebView::create(0); - m_webView->initializeMainFrame(WorkerWebFrameClient::sharedInstance()); - - WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame()); - - // Construct substitute data source for the 'shadow page'. We only need it - // to have same origin as the worker so the loading checks work correctly. - CString content(""); - int len = static_cast<int>(content.length()); - RefPtr<SharedBuffer> buf(SharedBuffer::create(content.data(), len)); - SubstituteData substData(buf, String("text/html"), String("UTF-8"), KURL()); - ResourceRequest request(scriptUrl, CString()); - webFrame->frame()->loader()->load(request, substData, false); - - // This document will be used as 'loading context' for the worker. - m_loadingDocument = webFrame->frame()->document(); - - m_workerThread = DedicatedWorkerThread::create(scriptUrl, userAgent, - sourceCode, *this, *this); + initializeLoader(scriptUrl); + setWorkerThread(DedicatedWorkerThread::create(scriptUrl, userAgent, + sourceCode, *this, *this)); // Worker initialization means a pending activity. reportPendingActivity(true); - m_workerThread->start(); + workerThread()->start(); } void WebWorkerImpl::terminateWorkerContext() { - if (m_askedToTerminate) - return; - m_askedToTerminate = true; - if (m_workerThread) - m_workerThread->stop(); + stopWorkerThread(); } void WebWorkerImpl::postMessageToWorkerContext(const WebString& message, @@ -197,7 +127,7 @@ void WebWorkerImpl::postMessageToWorkerContext(const WebString& message, } } - m_workerThread->runLoop().postTask( + workerThread()->runLoop().postTask( createCallbackTask(&postMessageToWorkerContextTask, this, String(message), channels.release())); } @@ -216,158 +146,6 @@ void WebWorkerImpl::clientDestroyed() m_client = 0; } -void WebWorkerImpl::dispatchTaskToMainThread(PassOwnPtr<ScriptExecutionContext::Task> task) -{ - return callOnMainThread(invokeTaskMethod, task.release()); -} - -void WebWorkerImpl::invokeTaskMethod(void* param) -{ - ScriptExecutionContext::Task* task = - static_cast<ScriptExecutionContext::Task*>(param); - task->performTask(0); - delete task; -} - -// WorkerObjectProxy ----------------------------------------------------------- - -void WebWorkerImpl::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> message, - PassOwnPtr<MessagePortChannelArray> channels) -{ - dispatchTaskToMainThread(createCallbackTask(&postMessageTask, this, - message->toString(), channels)); -} - -void WebWorkerImpl::postMessageTask(ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - String message, - PassOwnPtr<MessagePortChannelArray> channels) -{ - if (!thisPtr->m_client) - return; - - WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0); - for (size_t i = 0; i < webChannels.size(); ++i) { - webChannels[i] = (*channels)[i]->channel()->webChannelRelease(); - webChannels[i]->setClient(0); - } - - thisPtr->m_client->postMessageToWorkerObject(message, webChannels); -} - -void WebWorkerImpl::postExceptionToWorkerObject(const String& errorMessage, - int lineNumber, - const String& sourceURL) -{ - dispatchTaskToMainThread(createCallbackTask(&postExceptionTask, this, - errorMessage, lineNumber, - sourceURL)); -} - -void WebWorkerImpl::postExceptionTask(ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - const String& errorMessage, - int lineNumber, const String& sourceURL) -{ - if (!thisPtr->m_client) - return; - - thisPtr->m_client->postExceptionToWorkerObject(errorMessage, - lineNumber, - sourceURL); -} - -void WebWorkerImpl::postConsoleMessageToWorkerObject(MessageDestination destination, - MessageSource source, - MessageType type, - MessageLevel level, - const String& message, - int lineNumber, - const String& sourceURL) -{ - dispatchTaskToMainThread(createCallbackTask(&postConsoleMessageTask, this, - static_cast<int>(destination), - static_cast<int>(source), - static_cast<int>(type), - static_cast<int>(level), - message, lineNumber, sourceURL)); -} - -void WebWorkerImpl::postConsoleMessageTask(ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - int destination, int source, - int type, int level, - const String& message, - int lineNumber, - const String& sourceURL) -{ - if (!thisPtr->m_client) - return; - thisPtr->m_client->postConsoleMessageToWorkerObject(destination, source, - type, level, message, - lineNumber, sourceURL); -} - -void WebWorkerImpl::confirmMessageFromWorkerObject(bool hasPendingActivity) -{ - dispatchTaskToMainThread(createCallbackTask(&confirmMessageTask, this, - hasPendingActivity)); -} - -void WebWorkerImpl::confirmMessageTask(ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - bool hasPendingActivity) -{ - if (!thisPtr->m_client) - return; - thisPtr->m_client->confirmMessageFromWorkerObject(hasPendingActivity); -} - -void WebWorkerImpl::reportPendingActivity(bool hasPendingActivity) -{ - dispatchTaskToMainThread(createCallbackTask(&reportPendingActivityTask, - this, hasPendingActivity)); -} - -void WebWorkerImpl::reportPendingActivityTask(ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - bool hasPendingActivity) -{ - if (!thisPtr->m_client) - return; - thisPtr->m_client->reportPendingActivity(hasPendingActivity); -} - -void WebWorkerImpl::workerContextDestroyed() -{ - dispatchTaskToMainThread(createCallbackTask(&workerContextDestroyedTask, - this)); -} - -// WorkerLoaderProxy ----------------------------------------------------------- - -void WebWorkerImpl::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task> task) -{ - ASSERT(m_loadingDocument->isDocument()); - m_loadingDocument->postTask(task); -} - -void WebWorkerImpl::postTaskForModeToWorkerContext( - PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode) -{ - m_workerThread->runLoop().postTaskForMode(task, mode); -} - -void WebWorkerImpl::workerContextDestroyedTask(ScriptExecutionContext* context, - WebWorkerImpl* thisPtr) -{ - if (thisPtr->m_client) - thisPtr->m_client->workerContextDestroyed(); - // The lifetime of this proxy is controlled by the worker context. - delete thisPtr; -} - - #else WebWorker* WebWorker::create(WebWorkerClient* client) diff --git a/webkit/api/src/WebWorkerImpl.h b/webkit/api/src/WebWorkerImpl.h index 49215593..bec96cd 100644 --- a/webkit/api/src/WebWorkerImpl.h +++ b/webkit/api/src/WebWorkerImpl.h @@ -36,14 +36,8 @@ #if ENABLE(WORKERS) #include "ScriptExecutionContext.h" -#include "WorkerLoaderProxy.h" -#include "WorkerObjectProxy.h" -#include <wtf/PassOwnPtr.h> -#include <wtf/RefPtr.h> -namespace WebCore { -class WorkerThread; -} +#include "WebWorkerBase.h" namespace WebKit { class WebView; @@ -53,30 +47,10 @@ class WebView; // class converts the data types. When the WebCore::Worker object wants to call // WebCore::WorkerObjectProxy, this class will conver to Chrome data types first // and then call the supplied WebWorkerClient. -class WebWorkerImpl : public WebCore::WorkerObjectProxy - , public WebCore::WorkerLoaderProxy - , public WebWorker { +class WebWorkerImpl : public WebWorkerBase, public WebWorker { public: explicit WebWorkerImpl(WebWorkerClient* client); - // WebCore::WorkerObjectProxy methods: - virtual void postMessageToWorkerObject( - PassRefPtr<WebCore::SerializedScriptValue>, - PassOwnPtr<WebCore::MessagePortChannelArray>); - virtual void postExceptionToWorkerObject( - const WebCore::String&, int, const WebCore::String&); - virtual void postConsoleMessageToWorkerObject( - WebCore::MessageDestination, WebCore::MessageSource, WebCore::MessageType, - WebCore::MessageLevel, const WebCore::String&, int, const WebCore::String&); - virtual void confirmMessageFromWorkerObject(bool); - virtual void reportPendingActivity(bool); - virtual void workerContextDestroyed(); - - // WebCore::WorkerLoaderProxy methods: - virtual void postTaskToLoader(PassOwnPtr<WebCore::ScriptExecutionContext::Task>); - virtual void postTaskForModeToWorkerContext( - PassOwnPtr<WebCore::ScriptExecutionContext::Task>, const WebCore::String& mode); - // WebWorker methods: virtual void startWorkerContext(const WebURL&, const WebString&, const WebString&); virtual void terminateWorkerContext(); @@ -84,10 +58,9 @@ public: virtual void workerObjectDestroyed(); virtual void clientDestroyed(); - WebWorkerClient* client() {return m_client;} - - // Executes the given task on the main thread. - static void dispatchTaskToMainThread(PassOwnPtr<WebCore::ScriptExecutionContext::Task>); + // WebWorkerBase methods: + virtual WebWorkerClient* client() { return m_client; } + virtual WebCommonWorkerClient* commonClient(); private: virtual ~WebWorkerImpl(); @@ -99,51 +72,8 @@ private: const WebCore::String& message, PassOwnPtr<WebCore::MessagePortChannelArray> channels); - // Function used to invoke tasks on the main thread. - static void invokeTaskMethod(void*); - - // Tasks that are run on the main thread. - static void postMessageTask( - WebCore::ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - WebCore::String message, - PassOwnPtr<WebCore::MessagePortChannelArray> channels); - static void postExceptionTask( - WebCore::ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - const WebCore::String& message, - int lineNumber, - const WebCore::String& sourceURL); - static void postConsoleMessageTask( - WebCore::ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - int destination, - int source, - int type, - int level, - const WebCore::String& message, - int lineNumber, - const WebCore::String& sourceURL); - static void confirmMessageTask( - WebCore::ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - bool hasPendingActivity); - static void reportPendingActivityTask( - WebCore::ScriptExecutionContext* context, - WebWorkerImpl* thisPtr, - bool hasPendingActivity); - static void workerContextDestroyedTask( - WebCore::ScriptExecutionContext* context, - WebWorkerImpl* thisPtr); - WebWorkerClient* m_client; - // 'shadow page' - created to proxy loading requests from the worker. - RefPtr<WebCore::ScriptExecutionContext> m_loadingDocument; - WebView* m_webView; - bool m_askedToTerminate; - - RefPtr<WebCore::WorkerThread> m_workerThread; }; } // namespace WebKit diff --git a/webkit/tools/test_shell/test_web_worker.h b/webkit/tools/test_shell/test_web_worker.h index 2aa1a2a..46595f2 100644 --- a/webkit/tools/test_shell/test_web_worker.h +++ b/webkit/tools/test_shell/test_web_worker.h @@ -66,6 +66,7 @@ class TestWebWorker : public WebKit::WebWorker, } virtual void confirmMessageFromWorkerObject(bool has_pending_activity) { } virtual void reportPendingActivity(bool has_pending_activity) { } + virtual void workerContextClosed() { } virtual void workerContextDestroyed() { Release(); // Releases the reference held for worker context object. } |