Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Side by Side Diff: webkit/api/src/WebWorkerImpl.cpp

Issue 337057: Move webworker{client}_impl.{h,cc} into webkit/api/src (Closed)
Patch Set: mulitple workers per process comment fixed Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webkit/api/src/WebWorkerImpl.h ('k') | webkit/glue/empty_webframeclient.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "WebWorkerImpl.h"
33
34 #include "DedicatedWorkerContext.h"
35 #include "DedicatedWorkerThread.h"
36 #include "GenericWorkerTask.h"
37 #include "KURL.h"
38 #include "MessageEvent.h"
39 #include "MessagePort.h"
40 #include "MessagePortChannel.h"
41 #include "ScriptExecutionContext.h"
42 #include "SecurityOrigin.h"
43 #include "SerializedScriptValue.h"
44 #include "SubstituteData.h"
45 #include <wtf/MainThread.h>
46 #include <wtf/Threading.h>
47
48 #include "EmptyWebFrameClientImpl.h"
49 #include "PlatformMessagePortChannel.h"
50 #include "WebDataSourceImpl.h"
51 #include "WebFrameClient.h"
52 #include "WebMessagePortChannel.h"
53 #include "WebScreenInfo.h"
54 #include "WebString.h"
55 #include "WebURL.h"
56 #include "WebView.h"
57 #include "WebWorkerClient.h"
58 // FIXME: webframe should eventually move to api/src too.
59 #include "webkit/glue/webframe_impl.h"
60
61 using namespace WebCore;
62
63 namespace WebKit {
64
65 #if ENABLE(WORKERS)
66
67 // Dummy WebViewDelegate - we only need it in Worker process to load a
68 // 'shadow page' which will initialize WebCore loader.
69 class WorkerWebFrameClient : public WebKit::EmptyWebFrameClient {
70 public:
71 // Tell the loader to load the data into the 'shadow page' synchronously,
72 // so we can grab the resulting Document right after load.
73 virtual void didCreateDataSource(WebFrame* frame, WebDataSource* ds)
74 {
75 static_cast<WebDataSourceImpl*>(ds)->setDeferMainResourceDataLoad(false);
76 }
77
78 // Lazy allocate and leak this instance.
79 static WorkerWebFrameClient* sharedInstance()
80 {
81 static WorkerWebFrameClient client;
82 return &client;
83 }
84
85 private:
86 WorkerWebFrameClient()
87 {
88 }
89 };
90
91 WebWorker* WebWorker::create(WebWorkerClient* client)
92 {
93 return new WebWorkerImpl(client);
94 }
95
96 // This function is called on the main thread to force to initialize some static
97 // values used in WebKit before any worker thread is started. This is because in
98 // our worker processs, we do not run any WebKit code in main thread and thus
99 // when multiple workers try to start at the same time, we might hit crash due
100 // to contention for initializing static values.
101 void initializeWebKitStaticValues()
102 {
103 static bool initialized = false;
104 if (!initialized) {
105 initialized = true;
106 // Note that we have to pass a URL with valid protocol in order to follow
107 // the path to do static value initializations.
108 RefPtr<SecurityOrigin> origin =
109 SecurityOrigin::create(KURL(ParsedURLString, "http://localhost"));
110 origin.release();
111 }
112 }
113
114 WebWorkerImpl::WebWorkerImpl(WebWorkerClient* client)
115 : m_client(client)
116 , m_webView(0)
117 , m_askedToTerminate(false)
118 {
119 initializeWebKitStaticValues();
120 }
121
122 WebWorkerImpl::~WebWorkerImpl()
123 {
124 m_webView->close();
125 }
126
127 void WebWorkerImpl::postMessageToWorkerContextTask(WebCore::ScriptExecutionContext* context,
128 WebWorkerImpl* thisPtr,
129 const String& message,
130 PassOwnPtr<MessagePortChannelArray> channels)
131 {
132 ASSERT(context->isWorkerContext());
133 DedicatedWorkerContext* workerContext =
134 static_cast<DedicatedWorkerContext*>(context);
135
136 OwnPtr<MessagePortArray> ports =
137 MessagePort::entanglePorts(*context, channels.release());
138 RefPtr<SerializedScriptValue> serializedMessage =
139 SerializedScriptValue::create(message);
140 workerContext->dispatchEvent(MessageEvent::create(
141 ports.release(), serializedMessage.release()));
142 thisPtr->confirmMessageFromWorkerObject(workerContext->hasPendingActivity());
143 }
144
145 // WebWorker -------------------------------------------------------------------
146
147 void WebWorkerImpl::startWorkerContext(const WebURL& scriptUrl,
148 const WebString& userAgent,
149 const WebString& sourceCode)
150 {
151 // Create 'shadow page'. This page is never displayed, it is used to proxy the
152 // loading requests from the worker context to the rest of WebKit and Chromium
153 // infrastructure.
154 ASSERT(!m_webView);
155 m_webView = WebView::create(0);
156 m_webView->initializeMainFrame(WorkerWebFrameClient::sharedInstance());
157
158 WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
159
160 // Construct substitute data source for the 'shadow page'. We only need it
161 // to have same origin as the worker so the loading checks work correctly.
162 CString content("");
163 int len = static_cast<int>(content.length());
164 RefPtr<SharedBuffer> buf(SharedBuffer::create(content.data(), len));
165 SubstituteData substData(buf, String("text/html"), String("UTF-8"), KURL());
166 ResourceRequest request(scriptUrl, CString());
167 webFrame->frame()->loader()->load(request, substData, false);
168
169 // This document will be used as 'loading context' for the worker.
170 m_loadingDocument = webFrame->frame()->document();
171
172 m_workerThread = DedicatedWorkerThread::create(scriptUrl, userAgent,
173 sourceCode, *this, *this);
174 // Worker initialization means a pending activity.
175 reportPendingActivity(true);
176 m_workerThread->start();
177 }
178
179 void WebWorkerImpl::terminateWorkerContext()
180 {
181 if (m_askedToTerminate)
182 return;
183 m_askedToTerminate = true;
184 if (m_workerThread)
185 m_workerThread->stop();
186 }
187
188 void WebWorkerImpl::postMessageToWorkerContext(const WebString& message,
189 const WebMessagePortChannelArray& webChannels)
190 {
191 OwnPtr<MessagePortChannelArray> channels;
192 if (webChannels.size()) {
193 channels = new MessagePortChannelArray(webChannels.size());
194 for (size_t i = 0; i < webChannels.size(); ++i) {
195 RefPtr<PlatformMessagePortChannel> platform_channel =
196 PlatformMessagePortChannel::create(webChannels[i]);
197 webChannels[i]->setClient(platform_channel.get());
198 (*channels)[i] = MessagePortChannel::create(platform_channel);
199 }
200 }
201
202 m_workerThread->runLoop().postTask(
203 createCallbackTask(&postMessageToWorkerContextTask,
204 this, String(message), channels.release()));
205 }
206
207 void WebWorkerImpl::workerObjectDestroyed()
208 {
209 // Worker object in the renderer was destroyed, perhaps a result of GC.
210 // For us, it's a signal to start terminating the WorkerContext too.
211 // FIXME: when 'kill a worker' html5 spec algorithm is implemented, it
212 // should be used here instead of 'terminate a worker'.
213 terminateWorkerContext();
214 }
215
216 void WebWorkerImpl::clientDestroyed()
217 {
218 m_client = 0;
219 }
220
221 void WebWorkerImpl::dispatchTaskToMainThread(PassRefPtr<ScriptExecutionContext::Task> task)
222 {
223 return callOnMainThread(invokeTaskMethod, task.releaseRef());
224 }
225
226 void WebWorkerImpl::invokeTaskMethod(void* param)
227 {
228 ScriptExecutionContext::Task* task =
229 static_cast<ScriptExecutionContext::Task*>(param);
230 task->performTask(0);
231 task->deref();
232 }
233
234 // WorkerObjectProxy -----------------------------------------------------------
235
236 void WebWorkerImpl::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> message,
237 PassOwnPtr<MessagePortChannelArray> channels)
238 {
239 dispatchTaskToMainThread(createCallbackTask(&postMessageTask, this,
240 message->toString(), channels));
241 }
242
243 void WebWorkerImpl::postMessageTask(ScriptExecutionContext* context,
244 WebWorkerImpl* thisPtr,
245 String message,
246 PassOwnPtr<MessagePortChannelArray> channels)
247 {
248 if (!thisPtr->m_client)
249 return;
250
251 WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0);
252 for (size_t i = 0; i < webChannels.size(); ++i) {
253 webChannels[i] = (*channels)[i]->channel()->webChannelRelease();
254 webChannels[i]->setClient(0);
255 }
256
257 thisPtr->m_client->postMessageToWorkerObject(message, webChannels);
258 }
259
260 void WebWorkerImpl::postExceptionToWorkerObject(const String& errorMessage,
261 int lineNumber,
262 const String& sourceURL)
263 {
264 dispatchTaskToMainThread(createCallbackTask(&postExceptionTask, this,
265 errorMessage, lineNumber,
266 sourceURL));
267 }
268
269 void WebWorkerImpl::postExceptionTask(ScriptExecutionContext* context,
270 WebWorkerImpl* thisPtr,
271 const String& errorMessage,
272 int lineNumber, const String& sourceURL)
273 {
274 if (!thisPtr->m_client)
275 return;
276
277 thisPtr->m_client->postExceptionToWorkerObject(errorMessage,
278 lineNumber,
279 sourceURL);
280 }
281
282 void WebWorkerImpl::postConsoleMessageToWorkerObject(MessageDestination destination,
283 MessageSource source,
284 MessageType type,
285 MessageLevel level,
286 const String& message,
287 int lineNumber,
288 const String& sourceURL)
289 {
290 dispatchTaskToMainThread(createCallbackTask(&postConsoleMessageTask, this,
291 static_cast<int>(destination),
292 static_cast<int>(source),
293 static_cast<int>(type),
294 static_cast<int>(level),
295 message, lineNumber, sourceURL));
296 }
297
298 void WebWorkerImpl::postConsoleMessageTask(ScriptExecutionContext* context,
299 WebWorkerImpl* thisPtr,
300 int destination, int source,
301 int type, int level,
302 const String& message,
303 int lineNumber,
304 const String& sourceURL)
305 {
306 if (!thisPtr->m_client)
307 return;
308 thisPtr->m_client->postConsoleMessageToWorkerObject(destination, source,
309 type, level, message,
310 lineNumber, sourceURL);
311 }
312
313 void WebWorkerImpl::confirmMessageFromWorkerObject(bool hasPendingActivity)
314 {
315 dispatchTaskToMainThread(createCallbackTask(&confirmMessageTask, this,
316 hasPendingActivity));
317 }
318
319 void WebWorkerImpl::confirmMessageTask(ScriptExecutionContext* context,
320 WebWorkerImpl* thisPtr,
321 bool hasPendingActivity)
322 {
323 if (!thisPtr->m_client)
324 return;
325 thisPtr->m_client->confirmMessageFromWorkerObject(hasPendingActivity);
326 }
327
328 void WebWorkerImpl::reportPendingActivity(bool hasPendingActivity)
329 {
330 dispatchTaskToMainThread(createCallbackTask(&reportPendingActivityTask,
331 this, hasPendingActivity));
332 }
333
334 void WebWorkerImpl::reportPendingActivityTask(ScriptExecutionContext* context,
335 WebWorkerImpl* thisPtr,
336 bool hasPendingActivity)
337 {
338 if (!thisPtr->m_client)
339 return;
340 thisPtr->m_client->reportPendingActivity(hasPendingActivity);
341 }
342
343 void WebWorkerImpl::workerContextDestroyed()
344 {
345 dispatchTaskToMainThread(createCallbackTask(&workerContextDestroyedTask,
346 this));
347 }
348
349 // WorkerLoaderProxy -----------------------------------------------------------
350
351 void WebWorkerImpl::postTaskToLoader(PassRefPtr<ScriptExecutionContext::Task> task)
352 {
353 ASSERT(m_loadingDocument->isDocument());
354 m_loadingDocument->postTask(task);
355 }
356
357 void WebWorkerImpl::postTaskForModeToWorkerContext(
358 PassRefPtr<ScriptExecutionContext::Task> task, const String& mode)
359 {
360 m_workerThread->runLoop().postTaskForMode(task, mode);
361 }
362
363 void WebWorkerImpl::workerContextDestroyedTask(ScriptExecutionContext* context,
364 WebWorkerImpl* thisPtr)
365 {
366 if (thisPtr->m_client)
367 thisPtr->m_client->workerContextDestroyed();
368 // The lifetime of this proxy is controlled by the worker context.
369 delete thisPtr;
370 }
371
372
373 #else
374
375 WebWorker* WebWorker::create(WebWorkerClient* client)
376 {
377 return 0;
378 }
379
380 #endif // ENABLE(WORKERS)
381
382 } // namespace WebKit
OLDNEW
« no previous file with comments | « webkit/api/src/WebWorkerImpl.h ('k') | webkit/glue/empty_webframeclient.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698