2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "WebWorkerBase.h"
34 #include "CrossThreadTask.h"
35 #include "DatabaseTask.h"
37 #include "MessagePortChannel.h"
38 #include "PlatformMessagePortChannel.h"
39 #include "SecurityOrigin.h"
41 #include "WebDataSourceImpl.h"
42 #include "WebFileError.h"
43 #include "WebFrameClient.h"
44 #include "WebFrameImpl.h"
45 #include "WebMessagePortChannel.h"
46 #include "WebRuntimeFeatures.h"
47 #include "WebSettings.h"
49 #include "WebWorkerClient.h"
51 #include "WorkerContext.h"
52 #include "WorkerLoaderProxy.h"
53 #include "WorkerThread.h"
54 #include <wtf/MainThread.h>
56 using namespace WebCore;
62 // This function is called on the main thread to force to initialize some static
63 // values used in WebKit before any worker thread is started. This is because in
64 // our worker processs, we do not run any WebKit code in main thread and thus
65 // when multiple workers try to start at the same time, we might hit crash due
66 // to contention for initializing static values.
67 static void initializeWebKitStaticValues()
69 static bool initialized = false;
72 // Note that we have to pass a URL with valid protocol in order to follow
73 // the path to do static value initializations.
74 RefPtr<SecurityOrigin> origin =
75 SecurityOrigin::create(KURL(ParsedURLString, "http://localhost"));
80 WebWorkerBase::WebWorkerBase()
82 , m_askedToTerminate(false)
84 initializeWebKitStaticValues();
87 WebWorkerBase::~WebWorkerBase()
90 WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
92 webFrame->setClient(0);
96 void WebWorkerBase::stopWorkerThread()
98 if (m_askedToTerminate)
100 m_askedToTerminate = true;
102 m_workerThread->stop();
105 void WebWorkerBase::initializeLoader(const WebURL& url)
107 // Create 'shadow page'. This page is never displayed, it is used to proxy the
108 // loading requests from the worker context to the rest of WebKit and Chromium
111 m_webView = WebView::create(0);
112 m_webView->settings()->setOfflineWebApplicationCacheEnabled(WebRuntimeFeatures::isApplicationCacheEnabled());
113 // FIXME: Settings information should be passed to the Worker process from Browser process when the worker
114 // is created (similar to RenderThread::OnCreateNewView).
115 m_webView->settings()->setHixie76WebSocketProtocolEnabled(false);
116 m_webView->initializeMainFrame(this);
118 WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
120 // Construct substitute data source for the 'shadow page'. We only need it
121 // to have same origin as the worker so the loading checks work correctly.
123 int len = static_cast<int>(content.length());
124 RefPtr<SharedBuffer> buf(SharedBuffer::create(content.data(), len));
125 SubstituteData substData(buf, String("text/html"), String("UTF-8"), KURL());
126 webFrame->frame()->loader()->load(ResourceRequest(url), substData, false);
128 // This document will be used as 'loading context' for the worker.
129 m_loadingDocument = webFrame->frame()->document();
132 void WebWorkerBase::dispatchTaskToMainThread(PassOwnPtr<ScriptExecutionContext::Task> task)
134 callOnMainThread(invokeTaskMethod, task.leakPtr());
137 void WebWorkerBase::invokeTaskMethod(void* param)
139 ScriptExecutionContext::Task* task =
140 static_cast<ScriptExecutionContext::Task*>(param);
141 task->performTask(0);
145 void WebWorkerBase::didCreateDataSource(WebFrame*, WebDataSource* ds)
147 // Tell the loader to load the data into the 'shadow page' synchronously,
148 // so we can grab the resulting Document right after load.
149 static_cast<WebDataSourceImpl*>(ds)->setDeferMainResourceDataLoad(false);
152 WebApplicationCacheHost* WebWorkerBase::createApplicationCacheHost(WebFrame*, WebApplicationCacheHostClient* appcacheHostClient)
155 return commonClient()->createApplicationCacheHost(appcacheHostClient);
159 // WorkerObjectProxy -----------------------------------------------------------
161 void WebWorkerBase::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> message,
162 PassOwnPtr<MessagePortChannelArray> channels)
164 dispatchTaskToMainThread(createCallbackTask(&postMessageTask, AllowCrossThreadAccess(this),
165 message->toWireString(), channels));
168 void WebWorkerBase::postMessageTask(ScriptExecutionContext* context,
169 WebWorkerBase* thisPtr,
171 PassOwnPtr<MessagePortChannelArray> channels)
173 if (!thisPtr->client())
176 WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0);
177 for (size_t i = 0; i < webChannels.size(); ++i) {
178 webChannels[i] = (*channels)[i]->channel()->webChannelRelease();
179 webChannels[i]->setClient(0);
182 thisPtr->client()->postMessageToWorkerObject(message, webChannels);
185 void WebWorkerBase::postExceptionToWorkerObject(const String& errorMessage,
187 const String& sourceURL)
189 dispatchTaskToMainThread(
190 createCallbackTask(&postExceptionTask, AllowCrossThreadAccess(this),
191 errorMessage, lineNumber,
195 void WebWorkerBase::postExceptionTask(ScriptExecutionContext* context,
196 WebWorkerBase* thisPtr,
197 const String& errorMessage,
198 int lineNumber, const String& sourceURL)
200 if (!thisPtr->commonClient())
203 thisPtr->commonClient()->postExceptionToWorkerObject(errorMessage,
208 void WebWorkerBase::postConsoleMessageToWorkerObject(MessageSource source,
211 const String& message,
213 const String& sourceURL)
215 dispatchTaskToMainThread(createCallbackTask(&postConsoleMessageTask, AllowCrossThreadAccess(this),
217 message, lineNumber, sourceURL));
220 void WebWorkerBase::postConsoleMessageTask(ScriptExecutionContext* context,
221 WebWorkerBase* thisPtr,
224 const String& message,
226 const String& sourceURL)
228 if (!thisPtr->commonClient())
230 thisPtr->commonClient()->postConsoleMessageToWorkerObject(source,
231 type, level, message,
232 lineNumber, sourceURL);
235 void WebWorkerBase::postMessageToPageInspector(const String& message)
237 dispatchTaskToMainThread(createCallbackTask(&postMessageToPageInspectorTask, AllowCrossThreadAccess(this), message));
240 void WebWorkerBase::postMessageToPageInspectorTask(ScriptExecutionContext*, WebWorkerBase* thisPtr, const String& message)
242 if (!thisPtr->commonClient())
244 thisPtr->commonClient()->dispatchDevToolsMessage(message);
247 void WebWorkerBase::confirmMessageFromWorkerObject(bool hasPendingActivity)
249 dispatchTaskToMainThread(createCallbackTask(&confirmMessageTask, AllowCrossThreadAccess(this),
250 hasPendingActivity));
253 void WebWorkerBase::confirmMessageTask(ScriptExecutionContext* context,
254 WebWorkerBase* thisPtr,
255 bool hasPendingActivity)
257 if (!thisPtr->client())
259 thisPtr->client()->confirmMessageFromWorkerObject(hasPendingActivity);
262 void WebWorkerBase::reportPendingActivity(bool hasPendingActivity)
264 dispatchTaskToMainThread(createCallbackTask(&reportPendingActivityTask,
265 AllowCrossThreadAccess(this),
266 hasPendingActivity));
269 void WebWorkerBase::reportPendingActivityTask(ScriptExecutionContext* context,
270 WebWorkerBase* thisPtr,
271 bool hasPendingActivity)
273 if (!thisPtr->client())
275 thisPtr->client()->reportPendingActivity(hasPendingActivity);
278 void WebWorkerBase::workerContextClosed()
280 dispatchTaskToMainThread(createCallbackTask(&workerContextClosedTask,
281 AllowCrossThreadAccess(this)));
284 void WebWorkerBase::workerContextClosedTask(ScriptExecutionContext* context,
285 WebWorkerBase* thisPtr)
287 if (thisPtr->commonClient())
288 thisPtr->commonClient()->workerContextClosed();
290 thisPtr->stopWorkerThread();
293 void WebWorkerBase::workerContextDestroyed()
295 dispatchTaskToMainThread(createCallbackTask(&workerContextDestroyedTask,
296 AllowCrossThreadAccess(this)));
299 void WebWorkerBase::workerContextDestroyedTask(ScriptExecutionContext* context,
300 WebWorkerBase* thisPtr)
302 if (thisPtr->commonClient())
303 thisPtr->commonClient()->workerContextDestroyed();
304 // The lifetime of this proxy is controlled by the worker context.
308 // WorkerLoaderProxy -----------------------------------------------------------
310 void WebWorkerBase::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task> task)
312 ASSERT(m_loadingDocument->isDocument());
313 m_loadingDocument->postTask(task);
316 void WebWorkerBase::postTaskForModeToWorkerContext(
317 PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
319 m_workerThread->runLoop().postTaskForMode(task, mode);
322 #endif // ENABLE(WORKERS)
324 } // namespace WebKit