diff options
-rw-r--r-- | webkit/api/src/EmptyWebFrameClientImpl.h | 92 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerClientImpl.cpp | 414 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerClientImpl.h | 155 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerImpl.cpp | 382 | ||||
-rw-r--r-- | webkit/api/src/WebWorkerImpl.h | 153 | ||||
-rw-r--r-- | webkit/glue/empty_webframeclient.h | 113 | ||||
-rw-r--r-- | webkit/glue/webkitclient_impl.cc | 3 | ||||
-rw-r--r-- | webkit/glue/webworker_impl.cc | 409 | ||||
-rw-r--r-- | webkit/glue/webworker_impl.h | 142 | ||||
-rw-r--r-- | webkit/glue/webworkerclient_impl.cc | 408 | ||||
-rw-r--r-- | webkit/glue/webworkerclient_impl.h | 150 | ||||
-rw-r--r-- | webkit/webkit.gyp | 9 |
12 files changed, 1227 insertions, 1203 deletions
diff --git a/webkit/api/src/EmptyWebFrameClientImpl.h b/webkit/api/src/EmptyWebFrameClientImpl.h deleted file mode 100644 index fadeaff..0000000 --- a/webkit/api/src/EmptyWebFrameClientImpl.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 EmptyWebFrameClientImpl_h -#define EmptyWebFrameClientImpl_h - -#include "WebFrameClient.h" -#include "WebURLError.h" - -namespace WebKit { - -// Extend from this if you only need to override a few WebFrameClient methods. -class EmptyWebFrameClient : public WebFrameClient { -public: - virtual WebPlugin* createPlugin(WebFrame*, const WebPluginParams&) { return 0; } - virtual WebWorker* createWorker(WebFrame*, WebWorkerClient*) { return 0; } - virtual WebMediaPlayer* createMediaPlayer(WebFrame*, WebMediaPlayerClient*) { return 0; } - virtual void willClose(WebFrame*) {} - virtual void loadURLExternally(WebFrame*, const WebURLRequest&, WebNavigationPolicy) {} - virtual WebNavigationPolicy decidePolicyForNavigation( - WebFrame*, const WebURLRequest&, WebNavigationType, const WebNode&, - WebNavigationPolicy defaultPolicy, bool) { return defaultPolicy; } - virtual bool canHandleRequest(WebFrame*, const WebURLRequest&) { return true; } - virtual WebURLError cannotHandleRequestError(WebFrame*, const WebURLRequest&) { return WebURLError(); } - virtual WebURLError cancelledError(WebFrame*, const WebURLRequest&) { return WebURLError(); } - virtual void unableToImplementPolicyWithError(WebFrame*, const WebURLError&) {} - virtual void willSubmitForm(WebFrame*, const WebForm&) {} - virtual void willPerformClientRedirect(WebFrame*, const WebURL&, const WebURL&, double, double) {} - virtual void didCancelClientRedirect(WebFrame*) {} - virtual void didCompleteClientRedirect(WebFrame*, const WebURL& from) {} - virtual void didCreateDataSource(WebFrame*, WebDataSource*) {} - virtual void didStartProvisionalLoad(WebFrame*) {} - virtual void didReceiveServerRedirectForProvisionalLoad(WebFrame*) {} - virtual void didFailProvisionalLoad(WebFrame*, const WebURLError&) {} - virtual void didReceiveDocumentData(WebFrame*, const char*, size_t, bool&) {} - virtual void didCommitProvisionalLoad(WebFrame*, bool) {} - virtual void didClearWindowObject(WebFrame*) {} - virtual void didCreateDocumentElement(WebFrame*) {} - virtual void didReceiveTitle(WebFrame*, const WebString&) {} - virtual void didFinishDocumentLoad(WebFrame*) {} - virtual void didHandleOnloadEvents(WebFrame*) {} - virtual void didFailLoad(WebFrame*, const WebURLError&) {} - virtual void didFinishLoad(WebFrame*) {} - virtual void didChangeLocationWithinPage(WebFrame*, bool) {} - virtual void didUpdateCurrentHistoryItem(WebFrame*) {} - virtual void assignIdentifierToRequest(WebFrame*, unsigned, const WebURLRequest&) {} - virtual void willSendRequest(WebFrame*, unsigned, WebURLRequest&, const WebURLResponse&) {} - virtual void didReceiveResponse(WebFrame*, unsigned, const WebURLResponse&) {} - virtual void didFinishResourceLoad(WebFrame*, unsigned) {} - virtual void didFailResourceLoad(WebFrame*, unsigned, const WebURLError&) {} - virtual void didLoadResourceFromMemoryCache(WebFrame*, const WebURLRequest&, const WebURLResponse&) {} - virtual void didDisplayInsecureContent(WebFrame*) {} - virtual void didRunInsecureContent(WebFrame*, const WebSecurityOrigin&) {} - virtual void didExhaustMemoryAvailableForScript(WebFrame*) {} - virtual void didCreateScriptContext(WebFrame*) {} - virtual void didDestroyScriptContext(WebFrame*) {} - virtual void didCreateIsolatedScriptContext(WebFrame*) {} - virtual void didChangeContentsSize(WebFrame*, const WebSize&) {} - virtual void reportFindInPageMatchCount(int, int, bool) {} - virtual void reportFindInPageSelection(int, int, const WebRect&) {} -}; - -} // namespace WebKit - -#endif diff --git a/webkit/api/src/WebWorkerClientImpl.cpp b/webkit/api/src/WebWorkerClientImpl.cpp deleted file mode 100644 index 16d7134..0000000 --- a/webkit/api/src/WebWorkerClientImpl.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/* - * 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> -#undef LOG - -#include "PlatformMessagePortChannel.h" -#include "WebFrameClient.h" -#include "WebKit.h" -#include "WebKitClient.h" -#include "WebMessagePortChannel.h" -#include "WebString.h" -#include "WebURL.h" -#include "WebWorker.h" -#include "WebWorkerImpl.h" -// FIXME: remove the includes below -#include "webkit/glue/webframeloaderclient_impl.h" -#include "webkit/glue/webframe_impl.h" -#include "webkit/glue/webview_impl.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()) { - WebWorkerImpl::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()) { - WebWorkerImpl::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()) { - WebWorkerImpl::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. - WebWorkerImpl::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::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/api/src/WebWorkerClientImpl.h b/webkit/api/src/WebWorkerClientImpl.h deleted file mode 100644 index f524f02..0000000 --- a/webkit/api/src/WebWorkerClientImpl.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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 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; - uint32 m_unconfirmedMessageCount; - bool m_workerContextHadPendingActivity; - ThreadIdentifier m_workerThreadId; -}; - -} // namespace WebKit; - -#endif // ENABLE(WORKERS) - -#endif diff --git a/webkit/api/src/WebWorkerImpl.cpp b/webkit/api/src/WebWorkerImpl.cpp deleted file mode 100644 index 677fdea..0000000 --- a/webkit/api/src/WebWorkerImpl.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* - * 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/MainThread.h> -#include <wtf/Threading.h> - -#include "EmptyWebFrameClientImpl.h" -#include "PlatformMessagePortChannel.h" -#include "WebDataSourceImpl.h" -#include "WebFrameClient.h" -#include "WebMessagePortChannel.h" -#include "WebScreenInfo.h" -#include "WebString.h" -#include "WebURL.h" -#include "WebView.h" -#include "WebWorkerClient.h" -// FIXME: webframe should eventually move to api/src too. -#include "webkit/glue/webframe_impl.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 WebKit::EmptyWebFrameClient { -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(); -} - -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) -{ - // 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); - // Worker initialization means a pending activity. - reportPendingActivity(true); - m_workerThread->start(); -} - -void WebWorkerImpl::terminateWorkerContext() -{ - if (m_askedToTerminate) - return; - m_askedToTerminate = true; - if (m_workerThread) - m_workerThread->stop(); -} - -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); - } - } - - m_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; -} - -void WebWorkerImpl::dispatchTaskToMainThread(PassRefPtr<ScriptExecutionContext::Task> task) -{ - return callOnMainThread(invokeTaskMethod, task.releaseRef()); -} - -void WebWorkerImpl::invokeTaskMethod(void* param) -{ - ScriptExecutionContext::Task* task = - static_cast<ScriptExecutionContext::Task*>(param); - task->performTask(0); - task->deref(); -} - -// 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(PassRefPtr<ScriptExecutionContext::Task> task) -{ - ASSERT(m_loadingDocument->isDocument()); - m_loadingDocument->postTask(task); -} - -void WebWorkerImpl::postTaskForModeToWorkerContext( - PassRefPtr<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) -{ - return 0; -} - -#endif // ENABLE(WORKERS) - -} // namespace WebKit diff --git a/webkit/api/src/WebWorkerImpl.h b/webkit/api/src/WebWorkerImpl.h deleted file mode 100644 index 00024f2..0000000 --- a/webkit/api/src/WebWorkerImpl.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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 "WorkerLoaderProxy.h" -#include "WorkerObjectProxy.h" -#include <wtf/PassOwnPtr.h> -#include <wtf/RefPtr.h> - -namespace WebCore { -class WorkerThread; -} - -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 WebCore::WorkerObjectProxy - , public WebCore::WorkerLoaderProxy - , 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(PassRefPtr<WebCore::ScriptExecutionContext::Task>); - virtual void postTaskForModeToWorkerContext( - PassRefPtr<WebCore::ScriptExecutionContext::Task>, const WebCore::String& mode); - - // 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(); - - WebWorkerClient* client() {return m_client;} - - // Executes the given task on the main thread. - static void dispatchTaskToMainThread(PassRefPtr<WebCore::ScriptExecutionContext::Task>); - -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); - - // 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 - -#endif // ENABLE(WORKERS) - -#endif diff --git a/webkit/glue/empty_webframeclient.h b/webkit/glue/empty_webframeclient.h new file mode 100644 index 0000000..f4d746e --- /dev/null +++ b/webkit/glue/empty_webframeclient.h @@ -0,0 +1,113 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_GLUE_EMPTY_WEBFRAMECLIENT_H_ +#define WEBKIT_GLUE_EMPTY_WEBFRAMECLIENT_H_ + +#include "webkit/api/public/WebFrameClient.h" +#include "webkit/api/public/WebURLError.h" + +namespace webkit_glue { + +// Extend from this if you only need to override a few WebFrameClient methods. +class EmptyWebFrameClient : public WebKit::WebFrameClient { + public: + virtual WebKit::WebPlugin* createPlugin( + WebKit::WebFrame* frame, const WebKit::WebPluginParams& params) { + return NULL; } + virtual WebKit::WebWorker* createWorker( + WebKit::WebFrame* frame, WebKit::WebWorkerClient* client) { + return NULL; } + virtual WebKit::WebMediaPlayer* createMediaPlayer( + WebKit::WebFrame* frame, WebKit::WebMediaPlayerClient* client) { + return NULL; } + virtual void willClose(WebKit::WebFrame* frame) {} + virtual void loadURLExternally( + WebKit::WebFrame* frame, const WebKit::WebURLRequest& request, + WebKit::WebNavigationPolicy policy) {} + virtual WebKit::WebNavigationPolicy decidePolicyForNavigation( + WebKit::WebFrame* frame, const WebKit::WebURLRequest& request, + WebKit::WebNavigationType type, const WebKit::WebNode& originating_node, + WebKit::WebNavigationPolicy default_policy, bool is_redirect) { + return default_policy; } + virtual bool canHandleRequest( + WebKit::WebFrame*, const WebKit::WebURLRequest&) { return true; } + virtual WebKit::WebURLError cannotHandleRequestError( + WebKit::WebFrame*, const WebKit::WebURLRequest& request) { + return WebKit::WebURLError(); + } + virtual WebKit::WebURLError cancelledError( + WebKit::WebFrame*, const WebKit::WebURLRequest& request) { + return WebKit::WebURLError(); + } + virtual void unableToImplementPolicyWithError( + WebKit::WebFrame*, const WebKit::WebURLError&) {} + virtual void willSubmitForm(WebKit::WebFrame* frame, + const WebKit::WebForm& form) {} + virtual void willPerformClientRedirect( + WebKit::WebFrame* frame, const WebKit::WebURL& from, + const WebKit::WebURL& to, double interval, double fire_time) {} + virtual void didCancelClientRedirect(WebKit::WebFrame* frame) {} + virtual void didCompleteClientRedirect( + WebKit::WebFrame* frame, const WebKit::WebURL& from) {} + virtual void didCreateDataSource( + WebKit::WebFrame* frame, WebKit::WebDataSource* datasource) {} + virtual void didStartProvisionalLoad(WebKit::WebFrame* frame) {} + virtual void didReceiveServerRedirectForProvisionalLoad( + WebKit::WebFrame* frame) {} + virtual void didFailProvisionalLoad( + WebKit::WebFrame* frame, const WebKit::WebURLError& error) {} + virtual void didReceiveDocumentData( + WebKit::WebFrame* frame, const char* data, size_t length, + bool& prevent_default) {} + virtual void didCommitProvisionalLoad( + WebKit::WebFrame* frame, bool is_new_navigation) {} + virtual void didClearWindowObject(WebKit::WebFrame* frame) {} + virtual void didCreateDocumentElement(WebKit::WebFrame* frame) {} + virtual void didReceiveTitle( + WebKit::WebFrame* frame, const WebKit::WebString& title) {} + virtual void didFinishDocumentLoad(WebKit::WebFrame* frame) {} + virtual void didHandleOnloadEvents(WebKit::WebFrame* frame) {} + virtual void didFailLoad( + WebKit::WebFrame* frame, const WebKit::WebURLError& error) {} + virtual void didFinishLoad(WebKit::WebFrame* frame) {} + virtual void didChangeLocationWithinPage( + WebKit::WebFrame* frame, bool is_new_navigation) {} + virtual void didUpdateCurrentHistoryItem(WebKit::WebFrame* frame) {} + virtual void assignIdentifierToRequest( + WebKit::WebFrame* frame, unsigned identifier, + const WebKit::WebURLRequest& request) {} + virtual void willSendRequest( + WebKit::WebFrame* frame, unsigned identifier, + WebKit::WebURLRequest& request, + const WebKit::WebURLResponse& redirect_response) {} + virtual void didReceiveResponse( + WebKit::WebFrame* frame, unsigned identifier, + const WebKit::WebURLResponse& response) {} + virtual void didFinishResourceLoad( + WebKit::WebFrame* frame, unsigned identifier) {} + virtual void didFailResourceLoad( + WebKit::WebFrame* frame, unsigned identifier, + const WebKit::WebURLError& error) {} + virtual void didLoadResourceFromMemoryCache( + WebKit::WebFrame* frame, const WebKit::WebURLRequest& request, + const WebKit::WebURLResponse&) {} + virtual void didDisplayInsecureContent(WebKit::WebFrame* frame) {} + virtual void didRunInsecureContent( + WebKit::WebFrame* frame, const WebKit::WebSecurityOrigin& origin) {} + virtual void didExhaustMemoryAvailableForScript(WebKit::WebFrame* frame) {} + virtual void didCreateScriptContext(WebKit::WebFrame* frame) {} + virtual void didDestroyScriptContext(WebKit::WebFrame* frame) {} + virtual void didCreateIsolatedScriptContext(WebKit::WebFrame* frame) {} + virtual void didChangeContentsSize( + WebKit::WebFrame* frame, const WebKit::WebSize& size) {} + virtual void reportFindInPageMatchCount( + int identifier, int count, bool final_update) {} + virtual void reportFindInPageSelection( + int identifier, int ordinal, const WebKit::WebRect& selection) {} +}; + +} // namespace webkit_glue + +#endif // WEBKIT_GLUE_EMPTY_WEBFRAMECLIENT_H_ diff --git a/webkit/glue/webkitclient_impl.cc b/webkit/glue/webkitclient_impl.cc index 2cd05b3..2d2e27f 100644 --- a/webkit/glue/webkitclient_impl.cc +++ b/webkit/glue/webkitclient_impl.cc @@ -30,7 +30,6 @@ #include "webkit/api/public/WebString.h" #include "webkit/api/public/WebViewClient.h" #include "webkit/api/src/ChromeClientImpl.h" -#include "webkit/api/src/WebWorkerClientImpl.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/plugins/plugin_instance.h" #include "webkit/glue/webkit_glue.h" @@ -38,6 +37,7 @@ #include "webkit/glue/websocketstreamhandle_impl.h" #include "webkit/glue/weburlloader_impl.h" #include "webkit/glue/webview_impl.h" +#include "webkit/glue/webworkerclient_impl.h" using WebKit::ChromeClientImpl; using WebKit::WebApplicationCacheHost; @@ -52,7 +52,6 @@ using WebKit::WebSocketStreamHandle; using WebKit::WebThemeEngine; using WebKit::WebURLLoader; using WebKit::WebWidgetClient; -using WebKit::WebWorkerClientImpl; namespace { diff --git a/webkit/glue/webworker_impl.cc b/webkit/glue/webworker_impl.cc new file mode 100644 index 0000000..172ba4d --- /dev/null +++ b/webkit/glue/webworker_impl.cc @@ -0,0 +1,409 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.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/MainThread.h> +#include <wtf/Threading.h> + +#undef LOG + +#include "webkit/api/public/WebFrameClient.h" +#include "webkit/api/public/WebMessagePortChannel.h" +#include "webkit/api/public/WebScreenInfo.h" +#include "webkit/api/public/WebString.h" +#include "webkit/api/public/WebURL.h" +#include "webkit/api/public/WebView.h" +#include "webkit/api/public/WebWorkerClient.h" +#include "webkit/api/src/PlatformMessagePortChannel.h" +#include "webkit/api/src/WebDataSourceImpl.h" +#include "webkit/glue/empty_webframeclient.h" +#include "webkit/glue/glue_util.h" +#include "webkit/glue/webframe_impl.h" +#include "webkit/glue/webpreferences.h" +#include "webkit/glue/webworker_impl.h" + +using WebKit::WebCursorInfo; +using WebKit::WebDataSource; +using WebKit::WebDataSourceImpl; +using WebKit::WebFrame; +using WebKit::WebFrameClient; +using WebKit::WebMessagePortChannel; +using WebKit::WebMessagePortChannelArray; +using WebKit::WebNavigationPolicy; +using WebKit::WebRect; +using WebKit::WebScreenInfo; +using WebKit::WebString; +using WebKit::WebURL; +using WebKit::WebWorker; +using WebKit::WebWorkerClient; +using WebKit::WebView; + +#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_glue::EmptyWebFrameClient { + 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* GetSharedInstance() { + static WorkerWebFrameClient client; + return &client; + } + + private: + WorkerWebFrameClient() {} +}; + +namespace WebKit { + +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. + WTF::RefPtr<WebCore::SecurityOrigin> origin = + WebCore::SecurityOrigin::create(WebCore::KURL(WebCore::ParsedURLString, + "http://localhost")); + origin.release(); + } +} + +WebWorkerImpl::WebWorkerImpl(WebWorkerClient* client) + : client_(client), + web_view_(NULL), + asked_to_terminate_(false) { + InitializeWebKitStaticValues(); +} + +WebWorkerImpl::~WebWorkerImpl() { + web_view_->close(); +} + +void WebWorkerImpl::PostMessageToWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + const WebCore::String& message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels) { + ASSERT(context->isWorkerContext()); + WebCore::DedicatedWorkerContext* worker_context = + static_cast<WebCore::DedicatedWorkerContext*>(context); + + WTF::OwnPtr<WebCore::MessagePortArray> ports = + WebCore::MessagePort::entanglePorts(*context, channels.release()); + WTF::RefPtr<WebCore::SerializedScriptValue> serialized_message = + WebCore::SerializedScriptValue::create(message); + worker_context->dispatchEvent( + WebCore::MessageEvent::create(ports.release(), + serialized_message.release())); + + this_ptr->confirmMessageFromWorkerObject( + worker_context->hasPendingActivity()); +} + +// WebWorker ------------------------------------------------------------------- + +void WebWorkerImpl::startWorkerContext(const WebURL& script_url, + const WebString& user_agent, + const WebString& source_code) { + // 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(!web_view_); + web_view_ = WebView::create(NULL); + WebPreferences().Apply(web_view_); + web_view_->initializeMainFrame(WorkerWebFrameClient::GetSharedInstance()); + + WebFrameImpl* web_frame = static_cast<WebFrameImpl*>(web_view_->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. + WebCore::CString content(""); + int len = static_cast<int>(content.length()); + RefPtr<WebCore::SharedBuffer> buf( + WebCore::SharedBuffer::create(content.data(), len)); + WebCore::SubstituteData subst_data(buf, + WebCore::String("text/html"), + WebCore::String("UTF-8"), + WebCore::KURL()); + WebCore::ResourceRequest request(webkit_glue::GURLToKURL(script_url), + WebCore::CString()); + web_frame->frame()->loader()->load(request, subst_data, false); + + // This document will be used as 'loading context' for the worker. + loading_document_ = web_frame->frame()->document(); + + worker_thread_ = WebCore::DedicatedWorkerThread::create( + webkit_glue::WebURLToKURL(script_url), + webkit_glue::WebStringToString(user_agent), + webkit_glue::WebStringToString(source_code), + *this, + *this); + + // Worker initialization means a pending activity. + reportPendingActivity(true); + + worker_thread_->start(); +} + +void WebWorkerImpl::terminateWorkerContext() { + if (asked_to_terminate_) + return; + asked_to_terminate_ = true; + + if (worker_thread_) + worker_thread_->stop(); +} + +void WebWorkerImpl::postMessageToWorkerContext( + const WebString& message, + const WebMessagePortChannelArray& webchannels) { + + WTF::OwnPtr<WebCore::MessagePortChannelArray> channels; + if (webchannels.size()) { + channels = new WebCore::MessagePortChannelArray(webchannels.size()); + for (size_t i = 0; i < webchannels.size(); ++i) { + RefPtr<WebCore::PlatformMessagePortChannel> platform_channel = + WebCore::PlatformMessagePortChannel::create(webchannels[i]); + webchannels[i]->setClient(platform_channel.get()); + (*channels)[i] = WebCore::MessagePortChannel::create(platform_channel); + } + } + + worker_thread_->runLoop().postTask(WebCore::createCallbackTask( + &PostMessageToWorkerContextTask, + this, + webkit_glue::WebStringToString(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. + // TODO(dimich): when 'kill a worker' html5 spec algorithm is implemented, it + // should be used here instead of 'terminate a worker'. + terminateWorkerContext(); +} + +void WebWorkerImpl::clientDestroyed() { + client_ = NULL; +} + +void WebWorkerImpl::DispatchTaskToMainThread( + PassRefPtr<WebCore::ScriptExecutionContext::Task> task) { + return WTF::callOnMainThread(InvokeTaskMethod, task.releaseRef()); +} + +void WebWorkerImpl::InvokeTaskMethod(void* param) { + WebCore::ScriptExecutionContext::Task* task = + static_cast<WebCore::ScriptExecutionContext::Task*>(param); + task->performTask(NULL); + task->deref(); +} + +// WorkerObjectProxy ----------------------------------------------------------- + +void WebWorkerImpl::postMessageToWorkerObject( + WTF::PassRefPtr<WebCore::SerializedScriptValue> message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels) { + DispatchTaskToMainThread(WebCore::createCallbackTask( + &PostMessageTask, + this, + message->toString(), + channels)); +} + +void WebWorkerImpl::PostMessageTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + WebCore::String message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels) { + if (!this_ptr->client_) + return; + + WebMessagePortChannelArray web_channels( + channels.get() ? channels->size() : 0); + for (size_t i = 0; i < web_channels.size(); ++i) { + web_channels[i] = (*channels)[i]->channel()->webChannelRelease(); + web_channels[i]->setClient(0); + } + + this_ptr->client_->postMessageToWorkerObject( + webkit_glue::StringToWebString(message), web_channels); +} + +void WebWorkerImpl::postExceptionToWorkerObject( + const WebCore::String& error_message, + int line_number, + const WebCore::String& source_url) { + DispatchTaskToMainThread(WebCore::createCallbackTask( + &PostExceptionTask, + this, + error_message, + line_number, + source_url)); +} + +void WebWorkerImpl::PostExceptionTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + const WebCore::String& error_message, + int line_number, + const WebCore::String& source_url) { + if (!this_ptr->client_) + return; + + this_ptr->client_->postExceptionToWorkerObject( + webkit_glue::StringToWebString(error_message), + line_number, + webkit_glue::StringToWebString(source_url)); +} + +void WebWorkerImpl::postConsoleMessageToWorkerObject( + WebCore::MessageDestination destination, + WebCore::MessageSource source, + WebCore::MessageType type, + WebCore::MessageLevel level, + const WebCore::String& message, + int line_number, + const WebCore::String& source_url) { + DispatchTaskToMainThread(WebCore::createCallbackTask( + &PostConsoleMessageTask, + this, + static_cast<int>(destination), + static_cast<int>(source), + static_cast<int>(type), + static_cast<int>(level), + message, + line_number, + source_url)); +} + +void WebWorkerImpl::PostConsoleMessageTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + int destination, + int source, + int type, + int level, + const WebCore::String& message, + int line_number, + const WebCore::String& source_url) { + if (!this_ptr->client_) + return; + + this_ptr->client_->postConsoleMessageToWorkerObject( + destination, + source, + type, + level, + webkit_glue::StringToWebString(message), + line_number, + webkit_glue::StringToWebString(source_url)); +} + +void WebWorkerImpl::confirmMessageFromWorkerObject(bool has_pending_activity) { + DispatchTaskToMainThread(WebCore::createCallbackTask( + &ConfirmMessageTask, + this, + has_pending_activity)); +} + +void WebWorkerImpl::ConfirmMessageTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + bool has_pending_activity) { + if (!this_ptr->client_) + return; + + this_ptr->client_->confirmMessageFromWorkerObject(has_pending_activity); +} + +void WebWorkerImpl::reportPendingActivity(bool has_pending_activity) { + DispatchTaskToMainThread(WebCore::createCallbackTask( + &ReportPendingActivityTask, + this, + has_pending_activity)); +} + +void WebWorkerImpl::ReportPendingActivityTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + bool has_pending_activity) { + if (!this_ptr->client_) + return; + + this_ptr->client_->reportPendingActivity(has_pending_activity); +} + +void WebWorkerImpl::workerContextDestroyed() { + DispatchTaskToMainThread(WebCore::createCallbackTask( + &WorkerContextDestroyedTask, + this)); +} + +// WorkerLoaderProxy ----------------------------------------------------------- + +void WebWorkerImpl::postTaskToLoader( + PassRefPtr<WebCore::ScriptExecutionContext::Task> task) { + ASSERT(loading_document_->isDocument()); + loading_document_->postTask(task); +} + +void WebWorkerImpl::postTaskForModeToWorkerContext( + PassRefPtr<WebCore::ScriptExecutionContext::Task> task, + const WebCore::String& mode) { + worker_thread_->runLoop().postTaskForMode(task, mode); +} + +void WebWorkerImpl::WorkerContextDestroyedTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr) { + if (this_ptr->client_) + this_ptr->client_->workerContextDestroyed(); + + // The lifetime of this proxy is controlled by the worker context. + delete this_ptr; +} + +#else + +namespace WebKit { + +WebWorker* WebWorker::create(WebWorkerClient* client) { + return NULL; +} + +} + +#endif diff --git a/webkit/glue/webworker_impl.h b/webkit/glue/webworker_impl.h new file mode 100644 index 0000000..53c745a --- /dev/null +++ b/webkit/glue/webworker_impl.h @@ -0,0 +1,142 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_GLUE_WEBWORKER_IMPL_H_ +#define WEBKIT_GLUE_WEBWORKER_IMPL_H_ + +#include "webkit/api/public/WebWorker.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 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 WebCore::WorkerObjectProxy, + public WebCore::WorkerLoaderProxy, + public WebKit::WebWorker { + public: + explicit WebWorkerImpl(WebKit::WebWorkerClient* client); + + // WebCore::WorkerObjectProxy methods: + virtual void postMessageToWorkerObject( + WTF::PassRefPtr<WebCore::SerializedScriptValue> message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels); + virtual void postExceptionToWorkerObject( + const WebCore::String& error_message, + int line_number, + const WebCore::String& source_url); + virtual void postConsoleMessageToWorkerObject( + WebCore::MessageDestination destination, + WebCore::MessageSource source, + WebCore::MessageType type, + WebCore::MessageLevel level, + const WebCore::String& message, + int line_number, + const WebCore::String& source_url); + virtual void confirmMessageFromWorkerObject(bool has_pending_activity); + virtual void reportPendingActivity(bool has_pending_activity); + virtual void workerContextDestroyed(); + + // WebCore::WorkerLoaderProxy methods: + virtual void postTaskToLoader( + WTF::PassRefPtr<WebCore::ScriptExecutionContext::Task>); + virtual void postTaskForModeToWorkerContext( + WTF::PassRefPtr<WebCore::ScriptExecutionContext::Task>, + const WebCore::String& mode); + + // WebWorker methods: + virtual void startWorkerContext(const WebKit::WebURL& script_url, + const WebKit::WebString& user_agent, + const WebKit::WebString& source_code); + virtual void terminateWorkerContext(); + virtual void postMessageToWorkerContext( + const WebKit::WebString& message, + const WebKit::WebMessagePortChannelArray& channel); + virtual void workerObjectDestroyed(); + virtual void clientDestroyed(); + + WebKit::WebWorkerClient* client() { return client_; } + + // Executes the given task on the main thread. + static void DispatchTaskToMainThread( + PassRefPtr<WebCore::ScriptExecutionContext::Task> task); + + private: + virtual ~WebWorkerImpl(); + + // Tasks that are run on the worker thread. + static void PostMessageToWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + const WebCore::String& message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels); + + // Function used to invoke tasks on the main thread. + static void InvokeTaskMethod(void* param); + + // Tasks that are run on the main thread. + static void PostMessageTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + WebCore::String message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels); + static void PostExceptionTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + const WebCore::String& error_message, + int line_number, + const WebCore::String& source_url); + static void PostConsoleMessageTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + int destination, + int source, + int type, + int level, + const WebCore::String& message, + int line_number, + const WebCore::String& source_url); + static void ConfirmMessageTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + bool has_pending_activity); + static void ReportPendingActivityTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr, + bool has_pending_activity); + static void WorkerContextDestroyedTask( + WebCore::ScriptExecutionContext* context, + WebWorkerImpl* this_ptr); + + WebKit::WebWorkerClient* client_; + + // 'shadow page' - created to proxy loading requests from the worker. + WTF::RefPtr<WebCore::ScriptExecutionContext> loading_document_; + WebKit::WebView* web_view_; + bool asked_to_terminate_; + + WTF::RefPtr<WebCore::WorkerThread> worker_thread_; + + DISALLOW_COPY_AND_ASSIGN(WebWorkerImpl); +}; + +#endif + +#endif // WEBKIT_GLUE_WEBWORKER_IMPL_H_ diff --git a/webkit/glue/webworkerclient_impl.cc b/webkit/glue/webworkerclient_impl.cc new file mode 100644 index 0000000..d909fd2 --- /dev/null +++ b/webkit/glue/webworkerclient_impl.cc @@ -0,0 +1,408 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.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> + +#undef LOG + +#include "webkit/glue/webworkerclient_impl.h" + +#include "base/command_line.h" +#include "webkit/api/public/WebFrameClient.h" +#include "webkit/api/public/WebKit.h" +#include "webkit/api/public/WebKitClient.h" +#include "webkit/api/public/WebMessagePortChannel.h" +#include "webkit/api/public/WebString.h" +#include "webkit/api/public/WebURL.h" +#include "webkit/api/public/WebWorker.h" +#include "webkit/api/src/PlatformMessagePortChannel.h" +#include "webkit/glue/glue_util.h" +#include "webkit/glue/webframeloaderclient_impl.h" +#include "webkit/glue/webframe_impl.h" +#include "webkit/glue/webkitclient_impl.h" +#include "webkit/glue/webview_impl.h" +#include "webkit/glue/webworker_impl.h" + +using WebKit::WebFrameClient; +using WebKit::WebMessagePortChannel; +using WebKit::WebMessagePortChannelArray; +using WebKit::WebString; +using WebKit::WebWorker; +using WebKit::WebWorkerClient; + +// When WebKit creates a WorkerContextProxy object, we check if we're in the +// renderer or worker process. If the latter, then we just use +// WebCore::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 WebCore::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 +WebCore::WorkerContextProxy* WebWorkerClientImpl::createWorkerContextProxy( + WebCore::Worker* worker) { + if (!worker->scriptExecutionContext()->isDocument() && + CommandLine::ForCurrentProcess()->HasSwitch( + "web-worker-share-processes")) { + return new WebCore::WorkerMessagingProxy(worker); + } + + WebWorker* webworker = NULL; + WebWorkerClientImpl* proxy = new WebWorkerClientImpl(worker); + + if (worker->scriptExecutionContext()->isDocument()) { + WebCore::Document* document = static_cast<WebCore::Document*>( + worker->scriptExecutionContext()); + WebFrameImpl* webframe = WebFrameImpl::FromFrame(document->frame()); + webworker = webframe->client()->createWorker(webframe, proxy); + } else { + WebCore::WorkerContextExecutionProxy* current_context = + WebCore::WorkerContextExecutionProxy::retrieve(); + if (!current_context) { + NOTREACHED(); + return NULL; + } + + WebCore::DedicatedWorkerThread* thread = + static_cast<WebCore::DedicatedWorkerThread*>( + current_context->workerContext()->thread()); + WebCore::WorkerObjectProxy* worker_object_proxy = + &thread->workerObjectProxy(); + WebWorkerImpl* impl = reinterpret_cast<WebWorkerImpl*>(worker_object_proxy); + webworker = impl->client()->createWorker(proxy); + } + + proxy->set_webworker(webworker); + return proxy; +} + +WebWorkerClientImpl::WebWorkerClientImpl(WebCore::Worker* worker) + : script_execution_context_(worker->scriptExecutionContext()), + worker_(worker), + asked_to_terminate_(false), + unconfirmed_message_count_(0), + worker_context_had_pending_activity_(false), + worker_thread_id_(WTF::currentThread()) { +} + +WebWorkerClientImpl::~WebWorkerClientImpl() { +} + +void WebWorkerClientImpl::set_webworker(WebWorker* webworker) { + webworker_ = webworker; +} + +void WebWorkerClientImpl::startWorkerContext( + const WebCore::KURL& script_url, + const WebCore::String& user_agent, + const WebCore::String& source_code) { + // Worker.terminate() could be called from JS before the context is started. + if (asked_to_terminate_) + return; + + if (!WTF::isMainThread()) { + WebWorkerImpl::DispatchTaskToMainThread( + WebCore::createCallbackTask(&StartWorkerContextTask, this, + script_url.string(), user_agent, source_code)); + return; + } + + webworker_->startWorkerContext( + webkit_glue::KURLToWebURL(script_url), + webkit_glue::StringToWebString(user_agent), + webkit_glue::StringToWebString(source_code)); +} + +void WebWorkerClientImpl::terminateWorkerContext() { + if (asked_to_terminate_) + return; + + asked_to_terminate_ = true; + + if (!WTF::isMainThread()) { + WebWorkerImpl::DispatchTaskToMainThread( + WebCore::createCallbackTask(&TerminateWorkerContextTask, this)); + return; + } + + webworker_->terminateWorkerContext(); +} + +void WebWorkerClientImpl::postMessageToWorkerContext( + WTF::PassRefPtr<WebCore::SerializedScriptValue> message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels) { + // Worker.terminate() could be called from JS before the context is started. + if (asked_to_terminate_) + return; + + ++unconfirmed_message_count_; + + if (!WTF::isMainThread()) { + WebWorkerImpl::DispatchTaskToMainThread( + WebCore::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; + } + + webworker_->postMessageToWorkerContext( + webkit_glue::StringToWebString(message->toString()), webchannels); +} + +bool WebWorkerClientImpl::hasPendingActivity() const { + return !asked_to_terminate_ && + (unconfirmed_message_count_ || worker_context_had_pending_activity_); +} + +void WebWorkerClientImpl::workerObjectDestroyed() { + if (WTF::isMainThread()) { + webworker_->workerObjectDestroyed(); + worker_ = NULL; + } + + // 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( + WebCore::createCallbackTask(&WorkerObjectDestroyedTask, this)); +} + +void WebWorkerClientImpl::postMessageToWorkerObject( + const WebString& message, + const WebMessagePortChannelArray& channels) { + WebCore::String message2 = webkit_glue::WebStringToString(message); + OwnPtr<WebCore::MessagePortChannelArray> channels2; + if (channels.size()) { + channels2 = new WebCore::MessagePortChannelArray(channels.size()); + for (size_t i = 0; i < channels.size(); ++i) { + RefPtr<WebCore::PlatformMessagePortChannel> platform_channel = + WebCore::PlatformMessagePortChannel::create(channels[i]); + channels[i]->setClient(platform_channel.get()); + (*channels2)[i] = WebCore::MessagePortChannel::create(platform_channel); + } + } + + if (WTF::currentThread() != worker_thread_id_) { + script_execution_context_->postTask( + WebCore::createCallbackTask(&PostMessageToWorkerObjectTask, this, + message2, channels2.release())); + return; + } + + PostMessageToWorkerObjectTask( + script_execution_context_.get(), this, message2, channels2.release()); +} + +void WebWorkerClientImpl::postExceptionToWorkerObject( + const WebString& error_message, + int line_number, + const WebString& source_url) { + if (WTF::currentThread() != worker_thread_id_) { + script_execution_context_->postTask( + WebCore::createCallbackTask(&PostExceptionToWorkerObjectTask, this, + webkit_glue::WebStringToString(error_message), + line_number, + webkit_glue::WebStringToString(source_url))); + return; + } + + bool handled = false; + handled = worker_->dispatchEvent( + WebCore::ErrorEvent::create(webkit_glue::WebStringToString(error_message), + webkit_glue::WebStringToString(source_url), + line_number)); + if (!handled) + script_execution_context_->reportException( + webkit_glue::WebStringToString(error_message), + line_number, + webkit_glue::WebStringToString(source_url)); +} + +void WebWorkerClientImpl::postConsoleMessageToWorkerObject( + int destination_id, + int source_id, + int message_type, + int message_level, + const WebString& message, + int line_number, + const WebString& source_url) { + if (WTF::currentThread() != worker_thread_id_) { + script_execution_context_->postTask( + WebCore::createCallbackTask(&PostConsoleMessageToWorkerObjectTask, this, + destination_id, source_id, message_type, message_level, + webkit_glue::WebStringToString(message), + line_number, + webkit_glue::WebStringToString(source_url))); + return; + } + + script_execution_context_->addMessage( + static_cast<WebCore::MessageDestination>(destination_id), + static_cast<WebCore::MessageSource>(source_id), + static_cast<WebCore::MessageType>(message_type), + static_cast<WebCore::MessageLevel>(message_level), + webkit_glue::WebStringToString(message), + line_number, + webkit_glue::WebStringToString(source_url)); +} + +void WebWorkerClientImpl::confirmMessageFromWorkerObject( + bool has_pending_activity) { + // unconfirmed_message_count_ can only be updated on the thread where it's + // accessed. Otherwise there are race conditions with v8's garbage + // collection. + script_execution_context_->postTask( + WebCore::createCallbackTask(&ConfirmMessageFromWorkerObjectTask, this)); +} + +void WebWorkerClientImpl::reportPendingActivity(bool has_pending_activity) { + // See above comment in confirmMessageFromWorkerObject. + script_execution_context_->postTask( + WebCore::createCallbackTask(&ReportPendingActivityTask, this, + has_pending_activity)); +} + +void WebWorkerClientImpl::workerContextDestroyed() { +} + +void WebWorkerClientImpl::StartWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& script_url, + const WebCore::String& user_agent, + const WebCore::String& source_code) { + this_ptr->webworker_->startWorkerContext( + webkit_glue::KURLToWebURL( + WebCore::KURL(WebCore::ParsedURLString, script_url)), + webkit_glue::StringToWebString(user_agent), + webkit_glue::StringToWebString(source_code)); +} + +void WebWorkerClientImpl::TerminateWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr) { + this_ptr->webworker_->terminateWorkerContext(); +} + +void WebWorkerClientImpl::PostMessageToWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels) { + WebMessagePortChannelArray web_channels(channels.get() ? channels->size() : 0); + + for (size_t i = 0; i < web_channels.size(); ++i) { + web_channels[i] = (*channels)[i]->channel()->webChannelRelease(); + web_channels[i]->setClient(0); + } + + this_ptr->webworker_->postMessageToWorkerContext( + webkit_glue::StringToWebString(message), web_channels); +} + +void WebWorkerClientImpl::WorkerObjectDestroyedTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr) { + if (this_ptr->worker_) // Check we haven't alread called this. + this_ptr->webworker_->workerObjectDestroyed(); + delete this_ptr; +} + +void WebWorkerClientImpl::PostMessageToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels) { + + if (this_ptr->worker_) { + WTF::OwnPtr<WebCore::MessagePortArray> ports = + WebCore::MessagePort::entanglePorts(*context, channels.release()); + WTF::RefPtr<WebCore::SerializedScriptValue> serialized_message = + WebCore::SerializedScriptValue::create(message); + this_ptr->worker_->dispatchEvent( + WebCore::MessageEvent::create(ports.release(), + serialized_message.release())); + } +} + +void WebWorkerClientImpl::PostExceptionToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& error_message, + int line_number, + const WebCore::String& source_url) { + bool handled = false; + if (this_ptr->worker_) + handled = this_ptr->worker_->dispatchEvent( + WebCore::ErrorEvent::create(error_message, source_url, line_number)); + if (!handled) + this_ptr->script_execution_context_->reportException( + error_message, line_number, source_url); +} + +void WebWorkerClientImpl::PostConsoleMessageToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + int destination_id, + int source_id, + int message_type, + int message_level, + const WebCore::String& message, + int line_number, + const WebCore::String& source_url) { + this_ptr->script_execution_context_->addMessage( + static_cast<WebCore::MessageDestination>(destination_id), + static_cast<WebCore::MessageSource>(source_id), + static_cast<WebCore::MessageType>(message_type), + static_cast<WebCore::MessageLevel>(message_level), + message, + line_number, + source_url); +} + +void WebWorkerClientImpl::ConfirmMessageFromWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr) { + this_ptr->unconfirmed_message_count_--; +} + +void WebWorkerClientImpl::ReportPendingActivityTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + bool has_pending_activity) { + this_ptr->worker_context_had_pending_activity_ = has_pending_activity; +} + +#endif diff --git a/webkit/glue/webworkerclient_impl.h b/webkit/glue/webworkerclient_impl.h new file mode 100644 index 0000000..cb7938c --- /dev/null +++ b/webkit/glue/webworkerclient_impl.h @@ -0,0 +1,150 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_GLUE_WEBWORKERCLIENT_IMPL_H_ +#define WEBKIT_GLUE_WEBWORKERCLIENT_IMPL_H_ + +#if ENABLE(WORKERS) + +#include "webkit/api/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 WebKit::WebWorkerClient { + public: + WebWorkerClientImpl(WebCore::Worker* worker); + + // WebCore::WorkerContextProxy Factory. + static WebCore::WorkerContextProxy* createWorkerContextProxy( + WebCore::Worker* worker); + + void set_webworker(WebKit::WebWorker* 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& script_url, + const WebCore::String& user_agent, + const WebCore::String& source_code); + virtual void terminateWorkerContext(); + virtual void postMessageToWorkerContext( + WTF::PassRefPtr<WebCore::SerializedScriptValue> message, + WTF::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 WebKit::WebString& message, + const WebKit::WebMessagePortChannelArray& channels); + virtual void postExceptionToWorkerObject( + const WebKit::WebString& error_message, + int line_number, + const WebKit::WebString& source_url); + virtual void postConsoleMessageToWorkerObject( + int destination_id, + int source_id, + int message_type, + int message_level, + const WebKit::WebString& message, + int line_number, + const WebKit::WebString& source_url); + virtual void confirmMessageFromWorkerObject(bool has_pending_activity); + virtual void reportPendingActivity(bool has_pending_activity); + virtual void workerContextDestroyed(); + virtual WebKit::WebWorker* createWorker(WebKit::WebWorkerClient* client) { + return NULL; + } + virtual WebKit::WebNotificationPresenter* notificationPresenter() { + // TODO(johnnyg): Notifications not yet supported in workers. + // Coming soon. + return NULL; + } + + 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* this_ptr, + const WebCore::String& script_url, + const WebCore::String& user_agent, + const WebCore::String& source_code); + static void TerminateWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr); + static void PostMessageToWorkerContextTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels); + static void WorkerObjectDestroyedTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr); + + // 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* this_ptr, + const WebCore::String& message, + WTF::PassOwnPtr<WebCore::MessagePortChannelArray> channels); + static void PostExceptionToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + const WebCore::String& error_message, + int line_number, + const WebCore::String& source_url); + static void PostConsoleMessageToWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + int destination_id, + int source_id, + int message_type, + int message_level, + const WebCore::String& message, + int line_number, + const WebCore::String& source_url); + static void ConfirmMessageFromWorkerObjectTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr); + static void ReportPendingActivityTask( + WebCore::ScriptExecutionContext* context, + WebWorkerClientImpl* this_ptr, + bool has_pending_activity); + + // Guard against context from being destroyed before a worker exits. + WTF::RefPtr<WebCore::ScriptExecutionContext> script_execution_context_; + + WebCore::Worker* worker_; + WebKit::WebWorker* webworker_; + bool asked_to_terminate_; + uint32 unconfirmed_message_count_; + bool worker_context_had_pending_activity_; + WTF::ThreadIdentifier worker_thread_id_; +}; + +#endif + +#endif // WEBKIT_GLUE_WEBWORKERCLIENT_IMPL_H_ diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 0496315..aa22025 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -186,7 +186,6 @@ 'api/src/DragClientImpl.h', 'api/src/EditorClientImpl.cpp', 'api/src/EditorClientImpl.h', - 'api/src/EmptyWebFrameClientImpl.h', 'api/src/gtk/WebFontInfo.cpp', 'api/src/gtk/WebFontInfo.h', 'api/src/gtk/WebInputEventFactory.cpp', @@ -271,10 +270,6 @@ 'api/src/WebURLResponse.cpp', 'api/src/WebURLResponsePrivate.h', 'api/src/WebURLError.cpp', - 'api/src/WebWorkerClientImpl.cpp', - 'api/src/WebWorkerClientImpl.h', - 'api/src/WebWorkerImpl.cpp', - 'api/src/WebWorkerImpl.h', 'api/src/WrappedResourceRequest.h', 'api/src/WrappedResourceResponse.h', 'api/src/win/WebInputEventFactory.cpp', @@ -673,6 +668,10 @@ 'glue/weburlloader_impl.h', 'glue/webview_impl.cc', 'glue/webview_impl.h', + 'glue/webworker_impl.cc', + 'glue/webworker_impl.h', + 'glue/webworkerclient_impl.cc', + 'glue/webworkerclient_impl.h', 'glue/window_open_disposition.h', 'glue/window_open_disposition.cc', |