2009-11-10 Yaar Schnitman <yaar@chromium.org>
authoreric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Nov 2009 19:52:46 +0000 (19:52 +0000)
committereric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Nov 2009 19:52:46 +0000 (19:52 +0000)
        Reviewed by Dimitri Glazkov.

        Up-streaming Chromium API src files: WebWorker and friends.

        https://bugs.webkit.org/show_bug.cgi?id=31276

        * src/WebWorkerBase.cpp: Added.
        (WebKit::WorkerWebFrameClient::didCreateDataSource):
        (WebKit::WorkerWebFrameClient::sharedInstance):
        (WebKit::WorkerWebFrameClient::WorkerWebFrameClient):
        (WebKit::initializeWebKitStaticValues):
        (WebKit::WebWorkerBase::WebWorkerBase):
        (WebKit::WebWorkerBase::~WebWorkerBase):
        (WebKit::WebWorkerBase::stopWorkerThread):
        (WebKit::WebWorkerBase::initializeLoader):
        (WebKit::WebWorkerBase::dispatchTaskToMainThread):
        (WebKit::WebWorkerBase::invokeTaskMethod):
        (WebKit::WebWorkerBase::postMessageToWorkerObject):
        (WebKit::WebWorkerBase::postMessageTask):
        (WebKit::WebWorkerBase::postExceptionToWorkerObject):
        (WebKit::WebWorkerBase::postExceptionTask):
        (WebKit::WebWorkerBase::postConsoleMessageToWorkerObject):
        (WebKit::WebWorkerBase::postConsoleMessageTask):
        (WebKit::WebWorkerBase::confirmMessageFromWorkerObject):
        (WebKit::WebWorkerBase::confirmMessageTask):
        (WebKit::WebWorkerBase::reportPendingActivity):
        (WebKit::WebWorkerBase::reportPendingActivityTask):
        (WebKit::WebWorkerBase::workerContextClosed):
        (WebKit::WebWorkerBase::workerContextClosedTask):
        (WebKit::WebWorkerBase::workerContextDestroyed):
        (WebKit::WebWorkerBase::workerContextDestroyedTask):
        (WebKit::WebWorkerBase::postTaskToLoader):
        (WebKit::WebWorkerBase::postTaskForModeToWorkerContext):
        * src/WebWorkerBase.h: Added.
        (WebKit::WebWorkerBase::setWorkerThread):
        (WebKit::WebWorkerBase::workerThread):
        * src/WebWorkerClientImpl.cpp: Added.
        (WebKit::WebWorkerClientImpl::createWorkerContextProxy):
        (WebKit::WebWorkerClientImpl::WebWorkerClientImpl):
        (WebKit::WebWorkerClientImpl::~WebWorkerClientImpl):
        (WebKit::WebWorkerClientImpl::setWebWorker):
        (WebKit::WebWorkerClientImpl::startWorkerContext):
        (WebKit::WebWorkerClientImpl::terminateWorkerContext):
        (WebKit::WebWorkerClientImpl::postMessageToWorkerContext):
        (WebKit::WebWorkerClientImpl::hasPendingActivity):
        (WebKit::WebWorkerClientImpl::workerObjectDestroyed):
        (WebKit::WebWorkerClientImpl::postMessageToWorkerObject):
        (WebKit::WebWorkerClientImpl::postExceptionToWorkerObject):
        (WebKit::WebWorkerClientImpl::postConsoleMessageToWorkerObject):
        (WebKit::WebWorkerClientImpl::confirmMessageFromWorkerObject):
        (WebKit::WebWorkerClientImpl::reportPendingActivity):
        (WebKit::WebWorkerClientImpl::workerContextDestroyed):
        (WebKit::WebWorkerClientImpl::workerContextClosed):
        (WebKit::WebWorkerClientImpl::startWorkerContextTask):
        (WebKit::WebWorkerClientImpl::terminateWorkerContextTask):
        (WebKit::WebWorkerClientImpl::postMessageToWorkerContextTask):
        (WebKit::WebWorkerClientImpl::workerObjectDestroyedTask):
        (WebKit::WebWorkerClientImpl::postMessageToWorkerObjectTask):
        (WebKit::WebWorkerClientImpl::postExceptionToWorkerObjectTask):
        (WebKit::WebWorkerClientImpl::postConsoleMessageToWorkerObjectTask):
        (WebKit::WebWorkerClientImpl::confirmMessageFromWorkerObjectTask):
        (WebKit::WebWorkerClientImpl::reportPendingActivityTask):
        * src/WebWorkerClientImpl.h: Added.
        (WebKit::WebWorkerClientImpl::createWorker):
        (WebKit::WebWorkerClientImpl::notificationPresenter):
        * src/WebWorkerImpl.cpp: Added.
        (WebKit::WebWorker::create):
        (WebKit::WebWorkerImpl::WebWorkerImpl):
        (WebKit::WebWorkerImpl::~WebWorkerImpl):
        (WebKit::WebWorkerImpl::commonClient):
        (WebKit::WebWorkerImpl::postMessageToWorkerContextTask):
        (WebKit::WebWorkerImpl::startWorkerContext):
        (WebKit::WebWorkerImpl::terminateWorkerContext):
        (WebKit::WebWorkerImpl::postMessageToWorkerContext):
        (WebKit::WebWorkerImpl::workerObjectDestroyed):
        (WebKit::WebWorkerImpl::clientDestroyed):
        * src/WebWorkerImpl.h: Added.
        (WebKit::WebWorkerImpl::client):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@50751 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKit/chromium/ChangeLog
WebKit/chromium/src/WebWorkerBase.cpp [new file with mode: 0644]
WebKit/chromium/src/WebWorkerBase.h [new file with mode: 0644]
WebKit/chromium/src/WebWorkerClientImpl.cpp [new file with mode: 0644]
WebKit/chromium/src/WebWorkerClientImpl.h [new file with mode: 0644]
WebKit/chromium/src/WebWorkerImpl.cpp [new file with mode: 0644]
WebKit/chromium/src/WebWorkerImpl.h [new file with mode: 0644]

index 3560f7765fdbeced688ff424def73f5550c8718c..a73eb32ad601ef7b9d11b6e7d6ac00e17114cb55 100644 (file)
@@ -1,3 +1,84 @@
+2009-11-10  Yaar Schnitman  <yaar@chromium.org>
+
+        Reviewed by Dimitri Glazkov.
+
+        Up-streaming Chromium API src files: WebWorker and friends.
+
+        https://bugs.webkit.org/show_bug.cgi?id=31276
+
+        * src/WebWorkerBase.cpp: Added.
+        (WebKit::WorkerWebFrameClient::didCreateDataSource):
+        (WebKit::WorkerWebFrameClient::sharedInstance):
+        (WebKit::WorkerWebFrameClient::WorkerWebFrameClient):
+        (WebKit::initializeWebKitStaticValues):
+        (WebKit::WebWorkerBase::WebWorkerBase):
+        (WebKit::WebWorkerBase::~WebWorkerBase):
+        (WebKit::WebWorkerBase::stopWorkerThread):
+        (WebKit::WebWorkerBase::initializeLoader):
+        (WebKit::WebWorkerBase::dispatchTaskToMainThread):
+        (WebKit::WebWorkerBase::invokeTaskMethod):
+        (WebKit::WebWorkerBase::postMessageToWorkerObject):
+        (WebKit::WebWorkerBase::postMessageTask):
+        (WebKit::WebWorkerBase::postExceptionToWorkerObject):
+        (WebKit::WebWorkerBase::postExceptionTask):
+        (WebKit::WebWorkerBase::postConsoleMessageToWorkerObject):
+        (WebKit::WebWorkerBase::postConsoleMessageTask):
+        (WebKit::WebWorkerBase::confirmMessageFromWorkerObject):
+        (WebKit::WebWorkerBase::confirmMessageTask):
+        (WebKit::WebWorkerBase::reportPendingActivity):
+        (WebKit::WebWorkerBase::reportPendingActivityTask):
+        (WebKit::WebWorkerBase::workerContextClosed):
+        (WebKit::WebWorkerBase::workerContextClosedTask):
+        (WebKit::WebWorkerBase::workerContextDestroyed):
+        (WebKit::WebWorkerBase::workerContextDestroyedTask):
+        (WebKit::WebWorkerBase::postTaskToLoader):
+        (WebKit::WebWorkerBase::postTaskForModeToWorkerContext):
+        * src/WebWorkerBase.h: Added.
+        (WebKit::WebWorkerBase::setWorkerThread):
+        (WebKit::WebWorkerBase::workerThread):
+        * src/WebWorkerClientImpl.cpp: Added.
+        (WebKit::WebWorkerClientImpl::createWorkerContextProxy):
+        (WebKit::WebWorkerClientImpl::WebWorkerClientImpl):
+        (WebKit::WebWorkerClientImpl::~WebWorkerClientImpl):
+        (WebKit::WebWorkerClientImpl::setWebWorker):
+        (WebKit::WebWorkerClientImpl::startWorkerContext):
+        (WebKit::WebWorkerClientImpl::terminateWorkerContext):
+        (WebKit::WebWorkerClientImpl::postMessageToWorkerContext):
+        (WebKit::WebWorkerClientImpl::hasPendingActivity):
+        (WebKit::WebWorkerClientImpl::workerObjectDestroyed):
+        (WebKit::WebWorkerClientImpl::postMessageToWorkerObject):
+        (WebKit::WebWorkerClientImpl::postExceptionToWorkerObject):
+        (WebKit::WebWorkerClientImpl::postConsoleMessageToWorkerObject):
+        (WebKit::WebWorkerClientImpl::confirmMessageFromWorkerObject):
+        (WebKit::WebWorkerClientImpl::reportPendingActivity):
+        (WebKit::WebWorkerClientImpl::workerContextDestroyed):
+        (WebKit::WebWorkerClientImpl::workerContextClosed):
+        (WebKit::WebWorkerClientImpl::startWorkerContextTask):
+        (WebKit::WebWorkerClientImpl::terminateWorkerContextTask):
+        (WebKit::WebWorkerClientImpl::postMessageToWorkerContextTask):
+        (WebKit::WebWorkerClientImpl::workerObjectDestroyedTask):
+        (WebKit::WebWorkerClientImpl::postMessageToWorkerObjectTask):
+        (WebKit::WebWorkerClientImpl::postExceptionToWorkerObjectTask):
+        (WebKit::WebWorkerClientImpl::postConsoleMessageToWorkerObjectTask):
+        (WebKit::WebWorkerClientImpl::confirmMessageFromWorkerObjectTask):
+        (WebKit::WebWorkerClientImpl::reportPendingActivityTask):
+        * src/WebWorkerClientImpl.h: Added.
+        (WebKit::WebWorkerClientImpl::createWorker):
+        (WebKit::WebWorkerClientImpl::notificationPresenter):
+        * src/WebWorkerImpl.cpp: Added.
+        (WebKit::WebWorker::create):
+        (WebKit::WebWorkerImpl::WebWorkerImpl):
+        (WebKit::WebWorkerImpl::~WebWorkerImpl):
+        (WebKit::WebWorkerImpl::commonClient):
+        (WebKit::WebWorkerImpl::postMessageToWorkerContextTask):
+        (WebKit::WebWorkerImpl::startWorkerContext):
+        (WebKit::WebWorkerImpl::terminateWorkerContext):
+        (WebKit::WebWorkerImpl::postMessageToWorkerContext):
+        (WebKit::WebWorkerImpl::workerObjectDestroyed):
+        (WebKit::WebWorkerImpl::clientDestroyed):
+        * src/WebWorkerImpl.h: Added.
+        (WebKit::WebWorkerImpl::client):
+
 2009-11-10  Yaar Schnitman  <yaar@chromium.org>
 
         Reviewed by Dimitri Glazkov.
diff --git a/WebKit/chromium/src/WebWorkerBase.cpp b/WebKit/chromium/src/WebWorkerBase.cpp
new file mode 100644 (file)
index 0000000..85a263b
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * 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 "PlatformMessagePortChannel.h"
+
+#include "WebDataSourceImpl.h"
+#include "WebFrameClient.h"
+#include "WebFrameImpl.h"
+#include "WebMessagePortChannel.h"
+#include "WebView.h"
+#include "WebWorkerClient.h"
+
+#include "WorkerThread.h"
+#include <wtf/MainThread.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/chromium/src/WebWorkerBase.h b/WebKit/chromium/src/WebWorkerBase.h
new file mode 100644 (file)
index 0000000..0217401
--- /dev/null
@@ -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/chromium/src/WebWorkerClientImpl.cpp b/WebKit/chromium/src/WebWorkerClientImpl.cpp
new file mode 100644 (file)
index 0000000..6be03a7
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * 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 "WebWorkerClientImpl.h"
+
+#if ENABLE(WORKERS)
+
+#include "DedicatedWorkerThread.h"
+#include "ErrorEvent.h"
+#include "Frame.h"
+#include "FrameLoaderClient.h"
+#include "GenericWorkerTask.h"
+#include "MessageEvent.h"
+#include "MessagePort.h"
+#include "MessagePortChannel.h"
+#include "ScriptExecutionContext.h"
+#include "Worker.h"
+#include "WorkerContext.h"
+#include "WorkerContextExecutionProxy.h"
+#include "WorkerMessagingProxy.h"
+#include <wtf/Threading.h>
+
+#include "FrameLoaderClientImpl.h"
+#include "PlatformMessagePortChannel.h"
+#include "WebFrameClient.h"
+#include "WebFrameImpl.h"
+#include "WebKit.h"
+#include "WebKitClient.h"
+#include "WebMessagePortChannel.h"
+#include "WebString.h"
+#include "WebURL.h"
+#include "WebViewImpl.h"
+#include "WebWorker.h"
+#include "WebWorkerImpl.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+// When WebKit creates a WorkerContextProxy object, we check if we're in the
+// renderer or worker process.  If the latter, then we just use
+// WorkerMessagingProxy.
+//
+// If we're in the renderer process, then we need use the glue provided
+// WebWorker object to talk to the worker process over IPC.  The worker process
+// talks to Worker* using WorkerObjectProxy, which we implement on
+// WebWorkerClientImpl.
+//
+// Note that if we're running each worker in a separate process, then nested
+// workers end up using the same codepath as the renderer process.
+
+// static
+WorkerContextProxy* WebWorkerClientImpl::createWorkerContextProxy(Worker* worker)
+{
+    // Special behavior for multiple workers per process.
+    // FIXME: v8 doesn't support more than one workers per process.
+    // if (!worker->scriptExecutionContext()->isDocument())
+    //     return new WorkerMessagingProxy(worker);
+
+    WebWorker* webWorker = 0;
+    WebWorkerClientImpl* proxy = new WebWorkerClientImpl(worker);
+
+    if (worker->scriptExecutionContext()->isDocument()) {
+        Document* document = static_cast<Document*>(
+            worker->scriptExecutionContext());
+        WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame());
+        webWorker = webFrame->client()->createWorker(webFrame, proxy);
+    } else {
+        WorkerContextExecutionProxy* currentContext =
+        WorkerContextExecutionProxy::retrieve();
+        if (!currentContext) {
+            ASSERT_NOT_REACHED();
+            return 0;
+        }
+
+        DedicatedWorkerThread* thread =
+        static_cast<DedicatedWorkerThread*>(currentContext->workerContext()->thread());
+        WorkerObjectProxy* workerObjectProxy = &thread->workerObjectProxy();
+        WebWorkerImpl* impl = reinterpret_cast<WebWorkerImpl*>(workerObjectProxy);
+        webWorker = impl->client()->createWorker(proxy);
+    }
+
+    proxy->setWebWorker(webWorker);
+    return proxy;
+}
+
+WebWorkerClientImpl::WebWorkerClientImpl(Worker* worker)
+    : m_scriptExecutionContext(worker->scriptExecutionContext())
+    , m_worker(worker)
+    , m_askedToTerminate(false)
+    , m_unconfirmedMessageCount(0)
+    , m_workerContextHadPendingActivity(false)
+    , m_workerThreadId(currentThread())
+{
+}
+
+WebWorkerClientImpl::~WebWorkerClientImpl()
+{
+}
+
+void WebWorkerClientImpl::setWebWorker(WebWorker* webWorker)
+{
+    m_webWorker = webWorker;
+}
+
+void WebWorkerClientImpl::startWorkerContext(const KURL& scriptURL,
+                                             const String& userAgent,
+                                             const String& sourceCode)
+{
+    // Worker.terminate() could be called from JS before the context is started.
+    if (m_askedToTerminate)
+        return;
+    if (!isMainThread()) {
+        WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(
+            &startWorkerContextTask,
+            this,
+            scriptURL.string(),
+            userAgent,
+            sourceCode));
+        return;
+    }
+    m_webWorker->startWorkerContext(scriptURL, userAgent, sourceCode);
+}
+
+void WebWorkerClientImpl::terminateWorkerContext()
+{
+    if (m_askedToTerminate)
+        return;
+    m_askedToTerminate = true;
+    if (!isMainThread()) {
+        WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&terminateWorkerContextTask, this));
+        return;
+    }
+    m_webWorker->terminateWorkerContext();
+}
+
+void WebWorkerClientImpl::postMessageToWorkerContext(
+    PassRefPtr<SerializedScriptValue> message,
+    PassOwnPtr<MessagePortChannelArray> channels)
+{
+    // Worker.terminate() could be called from JS before the context is started.
+    if (m_askedToTerminate)
+        return;
+    ++m_unconfirmedMessageCount;
+    if (!isMainThread()) {
+        WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&postMessageToWorkerContextTask,
+                                                                   this,
+                                                                   message->toString(),
+                                                                   channels));
+        return;
+    }
+    WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0);
+    for (size_t i = 0; i < webChannels.size(); ++i) {
+        WebMessagePortChannel* webchannel =
+                        (*channels)[i]->channel()->webChannelRelease();
+        webchannel->setClient(0);
+        webChannels[i] = webchannel;
+    }
+    m_webWorker->postMessageToWorkerContext(message->toString(), webChannels);
+}
+
+bool WebWorkerClientImpl::hasPendingActivity() const
+{
+    return !m_askedToTerminate
+           && (m_unconfirmedMessageCount || m_workerContextHadPendingActivity);
+}
+
+void WebWorkerClientImpl::workerObjectDestroyed()
+{
+    if (isMainThread()) {
+        m_webWorker->workerObjectDestroyed();
+        m_worker = 0;
+    }
+    // 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.
+    WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&workerObjectDestroyedTask,
+                                                               this));
+}
+
+void WebWorkerClientImpl::postMessageToWorkerObject(const WebString& message,
+                                                    const WebMessagePortChannelArray& channels)
+{
+    OwnPtr<MessagePortChannelArray> channels2;
+    if (channels.size()) {
+        channels2 = new MessagePortChannelArray(channels.size());
+        for (size_t i = 0; i < channels.size(); ++i) {
+            RefPtr<PlatformMessagePortChannel> platform_channel =
+                            PlatformMessagePortChannel::create(channels[i]);
+            channels[i]->setClient(platform_channel.get());
+            (*channels2)[i] = MessagePortChannel::create(platform_channel);
+        }
+    }
+
+    if (currentThread() != m_workerThreadId) {
+        m_scriptExecutionContext->postTask(createCallbackTask(&postMessageToWorkerObjectTask,
+                                                              this,
+                                                              String(message),
+                                                              channels2.release()));
+        return;
+    }
+
+    postMessageToWorkerObjectTask(m_scriptExecutionContext.get(), this,
+                                  message, channels2.release());
+}
+
+void WebWorkerClientImpl::postExceptionToWorkerObject(const WebString& errorMessage,
+                                                      int lineNumber,
+                                                      const WebString& sourceURL)
+{
+    if (currentThread() != m_workerThreadId) {
+        m_scriptExecutionContext->postTask(createCallbackTask(&postExceptionToWorkerObjectTask,
+                                                              this,
+                                                              String(errorMessage),
+                                                              lineNumber,
+                                                              String(sourceURL)));
+        return;
+    }
+
+    bool handled = false;
+    handled = m_worker->dispatchEvent(ErrorEvent::create(errorMessage,
+                                                         sourceURL,
+                                                         lineNumber));
+    if (!handled)
+        m_scriptExecutionContext->reportException(errorMessage, lineNumber, sourceURL);
+}
+
+void WebWorkerClientImpl::postConsoleMessageToWorkerObject(int destinationId,
+                                                           int sourceId,
+                                                           int messageType,
+                                                           int messageLevel,
+                                                           const WebString& message,
+                                                           int lineNumber,
+                                                           const WebString& sourceURL)
+{
+    if (currentThread() != m_workerThreadId) {
+        m_scriptExecutionContext->postTask(createCallbackTask(&postConsoleMessageToWorkerObjectTask,
+                                                              this,
+                                                              destinationId,
+                                                              sourceId,
+                                                              messageType,
+                                                              messageLevel,
+                                                              String(message),
+                                                              lineNumber,
+                                                              String(sourceURL)));
+        return;
+    }
+
+    m_scriptExecutionContext->addMessage(static_cast<MessageDestination>(destinationId),
+                                         static_cast<MessageSource>(sourceId),
+                                         static_cast<MessageType>(messageType),
+                                         static_cast<MessageLevel>(messageLevel),
+                                         String(message), lineNumber,
+                                         String(sourceURL));
+}
+
+void WebWorkerClientImpl::confirmMessageFromWorkerObject(bool hasPendingActivity)
+{
+    // unconfirmed_message_count_ can only be updated on the thread where it's
+    // accessed.  Otherwise there are race conditions with v8's garbage
+    // collection.
+    m_scriptExecutionContext->postTask(createCallbackTask(&confirmMessageFromWorkerObjectTask,
+                                                          this));
+}
+
+void WebWorkerClientImpl::reportPendingActivity(bool hasPendingActivity)
+{
+    // See above comment in confirmMessageFromWorkerObject.
+    m_scriptExecutionContext->postTask(createCallbackTask(&reportPendingActivityTask,
+                                                          this,
+                                                          hasPendingActivity));
+}
+
+void WebWorkerClientImpl::workerContextDestroyed()
+{
+}
+
+void WebWorkerClientImpl::workerContextClosed()
+{
+}
+
+void WebWorkerClientImpl::startWorkerContextTask(ScriptExecutionContext* context,
+                                                 WebWorkerClientImpl* thisPtr,
+                                                 const String& scriptURL,
+                                                 const String& userAgent,
+                                                 const String& sourceCode)
+{
+    thisPtr->m_webWorker->startWorkerContext(KURL(ParsedURLString, scriptURL),
+                                             userAgent, sourceCode);
+}
+
+void WebWorkerClientImpl::terminateWorkerContextTask(ScriptExecutionContext* context,
+                                                     WebWorkerClientImpl* thisPtr)
+{
+    thisPtr->m_webWorker->terminateWorkerContext();
+}
+
+void WebWorkerClientImpl::postMessageToWorkerContextTask(ScriptExecutionContext* context,
+                                                         WebWorkerClientImpl* thisPtr,
+                                                         const String& message,
+                                                         PassOwnPtr<MessagePortChannelArray> channels)
+{
+    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_webWorker->postMessageToWorkerContext(message, webChannels);
+}
+
+void WebWorkerClientImpl::workerObjectDestroyedTask(ScriptExecutionContext* context,
+                                                    WebWorkerClientImpl* thisPtr)
+{
+    if (thisPtr->m_worker) // Check we haven't alread called this.
+        thisPtr->m_webWorker->workerObjectDestroyed();
+    delete thisPtr;
+}
+
+void WebWorkerClientImpl::postMessageToWorkerObjectTask(
+                                                        ScriptExecutionContext* context,
+                                                        WebWorkerClientImpl* thisPtr,
+                                                        const String& message,
+                                                        PassOwnPtr<MessagePortChannelArray> channels)
+{
+
+    if (thisPtr->m_worker) {
+        OwnPtr<MessagePortArray> ports =
+            MessagePort::entanglePorts(*context, channels.release());
+        RefPtr<SerializedScriptValue> serializedMessage =
+            SerializedScriptValue::create(message);
+        thisPtr->m_worker->dispatchEvent(MessageEvent::create(ports.release(),
+                                                              serializedMessage.release()));
+    }
+}
+
+void WebWorkerClientImpl::postExceptionToWorkerObjectTask(
+                                                          ScriptExecutionContext* context,
+                                                          WebWorkerClientImpl* thisPtr,
+                                                          const String& errorMessage,
+                                                          int lineNumber,
+                                                          const String& sourceURL)
+{
+    bool handled = false;
+    if (thisPtr->m_worker)
+        handled = thisPtr->m_worker->dispatchEvent(ErrorEvent::create(errorMessage,
+                                                                      sourceURL,
+                                                                      lineNumber));
+    if (!handled)
+        thisPtr->m_scriptExecutionContext->reportException(errorMessage,
+                                                           lineNumber,
+                                                           sourceURL);
+}
+
+void WebWorkerClientImpl::postConsoleMessageToWorkerObjectTask(ScriptExecutionContext* context,
+                                                               WebWorkerClientImpl* thisPtr,
+                                                               int destinationId,
+                                                               int sourceId,
+                                                               int messageType,
+                                                               int messageLevel,
+                                                               const String& message,
+                                                               int lineNumber,
+                                                               const String& sourceURL)
+{
+    thisPtr->m_scriptExecutionContext->addMessage(static_cast<MessageDestination>(destinationId),
+                                                  static_cast<MessageSource>(sourceId),
+                                                  static_cast<MessageType>(messageType),
+                                                  static_cast<MessageLevel>(messageLevel),
+                                                  message, lineNumber,
+                                                  sourceURL);
+}
+
+void WebWorkerClientImpl::confirmMessageFromWorkerObjectTask(ScriptExecutionContext* context,
+                                                             WebWorkerClientImpl* thisPtr)
+{
+    thisPtr->m_unconfirmedMessageCount--;
+}
+
+void WebWorkerClientImpl::reportPendingActivityTask(ScriptExecutionContext* context,
+                                                    WebWorkerClientImpl* thisPtr,
+                                                    bool hasPendingActivity)
+{
+    thisPtr->m_workerContextHadPendingActivity = hasPendingActivity;
+}
+
+} // namespace WebKit
+
+#endif
diff --git a/WebKit/chromium/src/WebWorkerClientImpl.h b/WebKit/chromium/src/WebWorkerClientImpl.h
new file mode 100644 (file)
index 0000000..63acebc
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * 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 WebWorkerClientImpl_h
+#define WebWorkerClientImpl_h
+
+#if ENABLE(WORKERS)
+
+// FIXME: fix to just "WebWorkerClient.h" once nobody in glue depends on us.
+#include "../public/WebWorkerClient.h"
+
+#include "WorkerContextProxy.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+class ScriptExecutionContext;
+}
+
+namespace WebKit {
+class WebWorker;
+
+// The purpose of this class is to provide a WorkerContextProxy
+// implementation that we can give to WebKit.  Internally, it converts the
+// data types to Chrome compatible ones so that renderer code can use it over
+// IPC.
+class WebWorkerClientImpl : public WebCore::WorkerContextProxy
+                          , public WebWorkerClient {
+public:
+    WebWorkerClientImpl(WebCore::Worker*);
+
+    // WebCore::WorkerContextProxy Factory.
+    static WebCore::WorkerContextProxy* createWorkerContextProxy(WebCore::Worker*);
+    void setWebWorker(WebWorker*);
+
+    // WebCore::WorkerContextProxy methods:
+    // These are called on the thread that created the worker.  In the renderer
+    // process, this will be the main WebKit thread.  In the worker process, this
+    // will be the thread of the executing worker (not the main WebKit thread).
+    virtual void startWorkerContext(const WebCore::KURL&,
+                                    const WebCore::String&,
+                                    const WebCore::String&);
+    virtual void terminateWorkerContext();
+    virtual void postMessageToWorkerContext(
+        PassRefPtr<WebCore::SerializedScriptValue> message,
+        PassOwnPtr<WebCore::MessagePortChannelArray> channels);
+    virtual bool hasPendingActivity() const;
+    virtual void workerObjectDestroyed();
+
+    // WebWorkerClient methods:
+    // These are called on the main WebKit thread.
+    virtual void postMessageToWorkerObject(const WebString&, const WebMessagePortChannelArray&);
+    virtual void postExceptionToWorkerObject(const WebString&, int, const WebString&);
+    virtual void postConsoleMessageToWorkerObject(int, int, int, int, const WebString&,
+                                                  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()
+    {
+        // FIXME: Notifications not yet supported in workers.
+        return 0;
+    }
+
+private:
+    virtual ~WebWorkerClientImpl();
+
+    // Methods used to support WebWorkerClientImpl being constructed on worker
+    // threads.
+    // These tasks are dispatched on the WebKit thread.
+    static void startWorkerContextTask(WebCore::ScriptExecutionContext* context,
+                                       WebWorkerClientImpl* thisPtr,
+                                       const WebCore::String& scriptURL,
+                                       const WebCore::String& userAgent,
+                                       const WebCore::String& sourceCode);
+    static void terminateWorkerContextTask(WebCore::ScriptExecutionContext* context,
+                                           WebWorkerClientImpl* thisPtr);
+    static void postMessageToWorkerContextTask(WebCore::ScriptExecutionContext* context,
+                                               WebWorkerClientImpl* thisPtr,
+                                               const WebCore::String& message,
+                                               PassOwnPtr<WebCore::MessagePortChannelArray> channels);
+    static void workerObjectDestroyedTask(WebCore::ScriptExecutionContext* context,
+                                          WebWorkerClientImpl* thisPtr);
+
+    // These tasks are dispatched on the thread that created the worker (i.e.
+    // main WebKit thread in renderer process, and the worker thread in the
+    // worker process).
+    static void postMessageToWorkerObjectTask(WebCore::ScriptExecutionContext* context,
+                                              WebWorkerClientImpl* thisPtr,
+                                              const WebCore::String& message,
+                                              PassOwnPtr<WebCore::MessagePortChannelArray> channels);
+    static void postExceptionToWorkerObjectTask(WebCore::ScriptExecutionContext* context,
+                                                WebWorkerClientImpl* thisPtr,
+                                                const WebCore::String& message,
+                                                int lineNumber,
+                                                const WebCore::String& sourceURL);
+    static void postConsoleMessageToWorkerObjectTask(WebCore::ScriptExecutionContext* context,
+                                                     WebWorkerClientImpl* thisPtr,
+                                                     int destinationId,
+                                                     int sourceId,
+                                                     int messageType,
+                                                     int messageLevel,
+                                                     const WebCore::String& message,
+                                                     int lineNumber,
+                                                     const WebCore::String& sourceURL);
+    static void confirmMessageFromWorkerObjectTask(WebCore::ScriptExecutionContext* context,
+                                                   WebWorkerClientImpl* thisPtr);
+    static void reportPendingActivityTask(WebCore::ScriptExecutionContext* context,
+                                          WebWorkerClientImpl* thisPtr,
+                                          bool hasPendingActivity);
+
+    // Guard against context from being destroyed before a worker exits.
+    RefPtr<WebCore::ScriptExecutionContext> m_scriptExecutionContext;
+
+    WebCore::Worker* m_worker;
+    WebWorker* m_webWorker;
+    bool m_askedToTerminate;
+    unsigned m_unconfirmedMessageCount;
+    bool m_workerContextHadPendingActivity;
+    ThreadIdentifier m_workerThreadId;
+};
+
+} // namespace WebKit;
+
+#endif // ENABLE(WORKERS)
+
+#endif
diff --git a/WebKit/chromium/src/WebWorkerImpl.cpp b/WebKit/chromium/src/WebWorkerImpl.cpp
new file mode 100644 (file)
index 0000000..744be30
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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 "WebWorkerImpl.h"
+
+#include "DedicatedWorkerContext.h"
+#include "DedicatedWorkerThread.h"
+#include "GenericWorkerTask.h"
+#include "KURL.h"
+#include "MessageEvent.h"
+#include "MessagePort.h"
+#include "MessagePortChannel.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
+#include "SerializedScriptValue.h"
+#include "SubstituteData.h"
+#include <wtf/Threading.h>
+
+#include "PlatformMessagePortChannel.h"
+#include "WebMessagePortChannel.h"
+#include "WebString.h"
+#include "WebURL.h"
+#include "WebWorkerClient.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+#if ENABLE(WORKERS)
+
+WebWorker* WebWorker::create(WebWorkerClient* client)
+{
+    return new WebWorkerImpl(client);
+}
+
+
+WebWorkerImpl::WebWorkerImpl(WebWorkerClient* client)
+    : m_client(client)
+{
+}
+
+WebWorkerImpl::~WebWorkerImpl()
+{
+}
+
+WebCommonWorkerClient* WebWorkerImpl::commonClient()
+{
+    return m_client;
+}
+
+void WebWorkerImpl::postMessageToWorkerContextTask(WebCore::ScriptExecutionContext* context,
+                                                   WebWorkerImpl* thisPtr,
+                                                   const String& message,
+                                                   PassOwnPtr<MessagePortChannelArray> channels)
+{
+    ASSERT(context->isWorkerContext());
+    DedicatedWorkerContext* workerContext =
+        static_cast<DedicatedWorkerContext*>(context);
+
+    OwnPtr<MessagePortArray> ports =
+        MessagePort::entanglePorts(*context, channels.release());
+    RefPtr<SerializedScriptValue> serializedMessage =
+        SerializedScriptValue::create(message);
+    workerContext->dispatchEvent(MessageEvent::create(
+        ports.release(), serializedMessage.release()));
+    thisPtr->confirmMessageFromWorkerObject(workerContext->hasPendingActivity());
+}
+
+// WebWorker -------------------------------------------------------------------
+
+void WebWorkerImpl::startWorkerContext(const WebURL& scriptUrl,
+                                       const WebString& userAgent,
+                                       const WebString& sourceCode)
+{
+    initializeLoader(scriptUrl);
+    setWorkerThread(DedicatedWorkerThread::create(scriptUrl, userAgent,
+                                                  sourceCode, *this, *this));
+    // Worker initialization means a pending activity.
+    reportPendingActivity(true);
+    workerThread()->start();
+}
+
+void WebWorkerImpl::terminateWorkerContext()
+{
+    stopWorkerThread();
+}
+
+void WebWorkerImpl::postMessageToWorkerContext(const WebString& message,
+                                               const WebMessagePortChannelArray& webChannels)
+{
+    OwnPtr<MessagePortChannelArray> channels;
+    if (webChannels.size()) {
+        channels = new MessagePortChannelArray(webChannels.size());
+        for (size_t i = 0; i < webChannels.size(); ++i) {
+            RefPtr<PlatformMessagePortChannel> platform_channel =
+                PlatformMessagePortChannel::create(webChannels[i]);
+            webChannels[i]->setClient(platform_channel.get());
+            (*channels)[i] = MessagePortChannel::create(platform_channel);
+        }
+    }
+
+    workerThread()->runLoop().postTask(
+        createCallbackTask(&postMessageToWorkerContextTask,
+                           this, String(message), channels.release()));
+}
+
+void WebWorkerImpl::workerObjectDestroyed()
+{
+    // Worker object in the renderer was destroyed, perhaps a result of GC.
+    // For us, it's a signal to start terminating the WorkerContext too.
+    // FIXME: when 'kill a worker' html5 spec algorithm is implemented, it
+    // should be used here instead of 'terminate a worker'.
+    terminateWorkerContext();
+}
+
+void WebWorkerImpl::clientDestroyed()
+{
+    m_client = 0;
+}
+
+#else
+
+WebWorker* WebWorker::create(WebWorkerClient* client)
+{
+    return 0;
+}
+
+#endif // ENABLE(WORKERS)
+
+} // namespace WebKit
diff --git a/WebKit/chromium/src/WebWorkerImpl.h b/WebKit/chromium/src/WebWorkerImpl.h
new file mode 100644 (file)
index 0000000..bec96cd
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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 WebWorkerImpl_h
+#define WebWorkerImpl_h
+
+#include "WebWorker.h"
+
+#if ENABLE(WORKERS)
+
+#include "ScriptExecutionContext.h"
+
+#include "WebWorkerBase.h"
+
+namespace WebKit {
+class WebView;
+
+// This class is used by the worker process code to talk to the WebCore::Worker
+// implementation.  It can't use it directly since it uses WebKit types, so this
+// 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 WebWorkerBase, public WebWorker {
+public:
+    explicit WebWorkerImpl(WebWorkerClient* client);
+
+    // WebWorker methods:
+    virtual void startWorkerContext(const WebURL&, const WebString&, const WebString&);
+    virtual void terminateWorkerContext();
+    virtual void postMessageToWorkerContext(const WebString&, const WebMessagePortChannelArray&);
+    virtual void workerObjectDestroyed();
+    virtual void clientDestroyed();
+
+    // WebWorkerBase methods:
+    virtual WebWorkerClient* client() { return m_client; }
+    virtual WebCommonWorkerClient* commonClient();
+
+private:
+    virtual ~WebWorkerImpl();
+
+    // Tasks that are run on the worker thread.
+    static void postMessageToWorkerContextTask(
+        WebCore::ScriptExecutionContext* context,
+        WebWorkerImpl* thisPtr,
+        const WebCore::String& message,
+        PassOwnPtr<WebCore::MessagePortChannelArray> channels);
+
+    WebWorkerClient* m_client;
+
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(WORKERS)
+
+#endif