initial import
[vuplus_webkit] / Source / WebKit / chromium / src / WebWorkerBase.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30
31 #include "config.h"
32 #include "WebWorkerBase.h"
33
34 #include "CrossThreadTask.h"
35 #include "DatabaseTask.h"
36 #include "Document.h"
37 #include "MessagePortChannel.h"
38 #include "PlatformMessagePortChannel.h"
39 #include "SecurityOrigin.h"
40
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"
48 #include "WebView.h"
49 #include "WebWorkerClient.h"
50
51 #include "WorkerContext.h"
52 #include "WorkerLoaderProxy.h"
53 #include "WorkerThread.h"
54 #include <wtf/MainThread.h>
55
56 using namespace WebCore;
57
58 namespace WebKit {
59
60 #if ENABLE(WORKERS)
61
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()
68 {
69     static bool initialized = false;
70     if (!initialized) {
71         initialized = true;
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"));
76         origin.release();
77     }
78 }
79
80 WebWorkerBase::WebWorkerBase()
81     : m_webView(0)
82     , m_askedToTerminate(false)
83 {
84     initializeWebKitStaticValues();
85 }
86
87 WebWorkerBase::~WebWorkerBase()
88 {
89     ASSERT(m_webView);
90     WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
91     if (webFrame)
92         webFrame->setClient(0);
93     m_webView->close();
94 }
95
96 void WebWorkerBase::stopWorkerThread()
97 {
98     if (m_askedToTerminate)
99         return;
100     m_askedToTerminate = true;
101     if (m_workerThread)
102         m_workerThread->stop();
103 }
104
105 void WebWorkerBase::initializeLoader(const WebURL& url)
106 {
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
109     // infrastructure.
110     ASSERT(!m_webView);
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);
117
118     WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
119
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.
122     CString content("");
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);
127
128     // This document will be used as 'loading context' for the worker.
129     m_loadingDocument = webFrame->frame()->document();
130 }
131
132 void WebWorkerBase::dispatchTaskToMainThread(PassOwnPtr<ScriptExecutionContext::Task> task)
133 {
134     callOnMainThread(invokeTaskMethod, task.leakPtr());
135 }
136
137 void WebWorkerBase::invokeTaskMethod(void* param)
138 {
139     ScriptExecutionContext::Task* task =
140         static_cast<ScriptExecutionContext::Task*>(param);
141     task->performTask(0);
142     delete task;
143 }
144
145 void WebWorkerBase::didCreateDataSource(WebFrame*, WebDataSource* ds)
146 {
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);
150 }
151
152 WebApplicationCacheHost* WebWorkerBase::createApplicationCacheHost(WebFrame*, WebApplicationCacheHostClient* appcacheHostClient)
153 {
154     if (commonClient())
155         return commonClient()->createApplicationCacheHost(appcacheHostClient);
156     return 0;
157 }
158
159 // WorkerObjectProxy -----------------------------------------------------------
160
161 void WebWorkerBase::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> message,
162                                               PassOwnPtr<MessagePortChannelArray> channels)
163 {
164     dispatchTaskToMainThread(createCallbackTask(&postMessageTask, AllowCrossThreadAccess(this),
165                                                 message->toWireString(), channels));
166 }
167
168 void WebWorkerBase::postMessageTask(ScriptExecutionContext* context,
169                                     WebWorkerBase* thisPtr,
170                                     String message,
171                                     PassOwnPtr<MessagePortChannelArray> channels)
172 {
173     if (!thisPtr->client())
174         return;
175
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);
180     }
181
182     thisPtr->client()->postMessageToWorkerObject(message, webChannels);
183 }
184
185 void WebWorkerBase::postExceptionToWorkerObject(const String& errorMessage,
186                                                 int lineNumber,
187                                                 const String& sourceURL)
188 {
189     dispatchTaskToMainThread(
190         createCallbackTask(&postExceptionTask, AllowCrossThreadAccess(this),
191                            errorMessage, lineNumber,
192                            sourceURL));
193 }
194
195 void WebWorkerBase::postExceptionTask(ScriptExecutionContext* context,
196                                       WebWorkerBase* thisPtr,
197                                       const String& errorMessage,
198                                       int lineNumber, const String& sourceURL)
199 {
200     if (!thisPtr->commonClient())
201         return;
202
203     thisPtr->commonClient()->postExceptionToWorkerObject(errorMessage,
204                                                          lineNumber,
205                                                          sourceURL);
206 }
207
208 void WebWorkerBase::postConsoleMessageToWorkerObject(MessageSource source,
209                                                      MessageType type,
210                                                      MessageLevel level,
211                                                      const String& message,
212                                                      int lineNumber,
213                                                      const String& sourceURL)
214 {
215     dispatchTaskToMainThread(createCallbackTask(&postConsoleMessageTask, AllowCrossThreadAccess(this),
216                                                 source, type, level,
217                                                 message, lineNumber, sourceURL));
218 }
219
220 void WebWorkerBase::postConsoleMessageTask(ScriptExecutionContext* context,
221                                            WebWorkerBase* thisPtr,
222                                            int source,
223                                            int type, int level,
224                                            const String& message,
225                                            int lineNumber,
226                                            const String& sourceURL)
227 {
228     if (!thisPtr->commonClient())
229         return;
230     thisPtr->commonClient()->postConsoleMessageToWorkerObject(source,
231                                                               type, level, message,
232                                                               lineNumber, sourceURL);
233 }
234
235 void WebWorkerBase::postMessageToPageInspector(const String& message)
236 {
237     dispatchTaskToMainThread(createCallbackTask(&postMessageToPageInspectorTask, AllowCrossThreadAccess(this), message));
238 }
239
240 void WebWorkerBase::postMessageToPageInspectorTask(ScriptExecutionContext*, WebWorkerBase* thisPtr, const String& message)
241 {
242     if (!thisPtr->commonClient())
243         return;
244     thisPtr->commonClient()->dispatchDevToolsMessage(message);
245 }
246
247 void WebWorkerBase::confirmMessageFromWorkerObject(bool hasPendingActivity)
248 {
249     dispatchTaskToMainThread(createCallbackTask(&confirmMessageTask, AllowCrossThreadAccess(this),
250                                                 hasPendingActivity));
251 }
252
253 void WebWorkerBase::confirmMessageTask(ScriptExecutionContext* context,
254                                        WebWorkerBase* thisPtr,
255                                        bool hasPendingActivity)
256 {
257     if (!thisPtr->client())
258         return;
259     thisPtr->client()->confirmMessageFromWorkerObject(hasPendingActivity);
260 }
261
262 void WebWorkerBase::reportPendingActivity(bool hasPendingActivity)
263 {
264     dispatchTaskToMainThread(createCallbackTask(&reportPendingActivityTask,
265                                                 AllowCrossThreadAccess(this),
266                                                 hasPendingActivity));
267 }
268
269 void WebWorkerBase::reportPendingActivityTask(ScriptExecutionContext* context,
270                                               WebWorkerBase* thisPtr,
271                                               bool hasPendingActivity)
272 {
273     if (!thisPtr->client())
274         return;
275     thisPtr->client()->reportPendingActivity(hasPendingActivity);
276 }
277
278 void WebWorkerBase::workerContextClosed()
279 {
280     dispatchTaskToMainThread(createCallbackTask(&workerContextClosedTask,
281                                                 AllowCrossThreadAccess(this)));
282 }
283
284 void WebWorkerBase::workerContextClosedTask(ScriptExecutionContext* context,
285                                             WebWorkerBase* thisPtr)
286 {
287     if (thisPtr->commonClient())
288         thisPtr->commonClient()->workerContextClosed();
289
290     thisPtr->stopWorkerThread();
291 }
292
293 void WebWorkerBase::workerContextDestroyed()
294 {
295     dispatchTaskToMainThread(createCallbackTask(&workerContextDestroyedTask,
296                                                 AllowCrossThreadAccess(this)));
297 }
298
299 void WebWorkerBase::workerContextDestroyedTask(ScriptExecutionContext* context,
300                                                WebWorkerBase* thisPtr)
301 {
302     if (thisPtr->commonClient())
303         thisPtr->commonClient()->workerContextDestroyed();
304     // The lifetime of this proxy is controlled by the worker context.
305     delete thisPtr;
306 }
307
308 // WorkerLoaderProxy -----------------------------------------------------------
309
310 void WebWorkerBase::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task> task)
311 {
312     ASSERT(m_loadingDocument->isDocument());
313     m_loadingDocument->postTask(task);
314 }
315
316 void WebWorkerBase::postTaskForModeToWorkerContext(
317     PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
318 {
319     m_workerThread->runLoop().postTaskForMode(task, mode);
320 }
321
322 #endif // ENABLE(WORKERS)
323
324 } // namespace WebKit