OLD | NEW |
| (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 "WebWorkerBase.h" | |
33 | |
34 #include "GenericWorkerTask.h" | |
35 #include "MessagePortChannel.h" | |
36 #include "PlatformMessagePortChannel.h" | |
37 | |
38 #include "WebDataSourceImpl.h" | |
39 #include "WebFrameClient.h" | |
40 #include "WebFrameImpl.h" | |
41 #include "WebMessagePortChannel.h" | |
42 #include "WebView.h" | |
43 #include "WebWorkerClient.h" | |
44 | |
45 #include "WorkerThread.h" | |
46 #include <wtf/MainThread.h> | |
47 | |
48 using namespace WebCore; | |
49 | |
50 namespace WebKit { | |
51 | |
52 #if ENABLE(WORKERS) | |
53 | |
54 // Dummy WebViewDelegate - we only need it in Worker process to load a | |
55 // 'shadow page' which will initialize WebCore loader. | |
56 class WorkerWebFrameClient : public WebFrameClient { | |
57 public: | |
58 // Tell the loader to load the data into the 'shadow page' synchronously, | |
59 // so we can grab the resulting Document right after load. | |
60 virtual void didCreateDataSource(WebFrame* frame, WebDataSource* ds) | |
61 { | |
62 static_cast<WebDataSourceImpl*>(ds)->setDeferMainResourceDataLoad(false); | |
63 } | |
64 | |
65 // Lazy allocate and leak this instance. | |
66 static WorkerWebFrameClient* sharedInstance() | |
67 { | |
68 static WorkerWebFrameClient client; | |
69 return &client; | |
70 } | |
71 | |
72 private: | |
73 WorkerWebFrameClient() | |
74 { | |
75 } | |
76 }; | |
77 | |
78 // This function is called on the main thread to force to initialize some static | |
79 // values used in WebKit before any worker thread is started. This is because in | |
80 // our worker processs, we do not run any WebKit code in main thread and thus | |
81 // when multiple workers try to start at the same time, we might hit crash due | |
82 // to contention for initializing static values. | |
83 static void initializeWebKitStaticValues() | |
84 { | |
85 static bool initialized = false; | |
86 if (!initialized) { | |
87 initialized = true; | |
88 // Note that we have to pass a URL with valid protocol in order to follow | |
89 // the path to do static value initializations. | |
90 RefPtr<SecurityOrigin> origin = | |
91 SecurityOrigin::create(KURL(ParsedURLString, "http://localhost")); | |
92 origin.release(); | |
93 } | |
94 } | |
95 | |
96 WebWorkerBase::WebWorkerBase() | |
97 : m_webView(0) | |
98 , m_askedToTerminate(false) | |
99 { | |
100 initializeWebKitStaticValues(); | |
101 } | |
102 | |
103 WebWorkerBase::~WebWorkerBase() | |
104 { | |
105 ASSERT(m_webView); | |
106 m_webView->close(); | |
107 } | |
108 | |
109 void WebWorkerBase::stopWorkerThread() | |
110 { | |
111 if (m_askedToTerminate) | |
112 return; | |
113 m_askedToTerminate = true; | |
114 if (m_workerThread) | |
115 m_workerThread->stop(); | |
116 } | |
117 | |
118 void WebWorkerBase::initializeLoader(const WebURL& url) | |
119 { | |
120 // Create 'shadow page'. This page is never displayed, it is used to proxy the | |
121 // loading requests from the worker context to the rest of WebKit and Chromium | |
122 // infrastructure. | |
123 ASSERT(!m_webView); | |
124 m_webView = WebView::create(0); | |
125 m_webView->initializeMainFrame(WorkerWebFrameClient::sharedInstance()); | |
126 | |
127 WebFrameImpl* webFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame()); | |
128 | |
129 // Construct substitute data source for the 'shadow page'. We only need it | |
130 // to have same origin as the worker so the loading checks work correctly. | |
131 CString content(""); | |
132 int len = static_cast<int>(content.length()); | |
133 RefPtr<SharedBuffer> buf(SharedBuffer::create(content.data(), len)); | |
134 SubstituteData substData(buf, String("text/html"), String("UTF-8"), KURL()); | |
135 ResourceRequest request(url, CString()); | |
136 webFrame->frame()->loader()->load(request, substData, false); | |
137 | |
138 // This document will be used as 'loading context' for the worker. | |
139 m_loadingDocument = webFrame->frame()->document(); | |
140 } | |
141 | |
142 void WebWorkerBase::dispatchTaskToMainThread(PassOwnPtr<ScriptExecutionContext::Task> task) | |
143 { | |
144 return callOnMainThread(invokeTaskMethod, task.release()); | |
145 } | |
146 | |
147 void WebWorkerBase::invokeTaskMethod(void* param) | |
148 { | |
149 ScriptExecutionContext::Task* task = | |
150 static_cast<ScriptExecutionContext::Task*>(param); | |
151 task->performTask(0); | |
152 delete task; | |
153 } | |
154 | |
155 // WorkerObjectProxy ----------------------------------------------------------- | |
156 | |
157 void WebWorkerBase::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> message, | |
158 PassOwnPtr<MessagePortChannelArray> channels) | |
159 { | |
160 dispatchTaskToMainThread(createCallbackTask(&postMessageTask, this, | |
161 message->toString(), channels)); | |
162 } | |
163 | |
164 void WebWorkerBase::postMessageTask(ScriptExecutionContext* context, | |
165 WebWorkerBase* thisPtr, | |
166 String message, | |
167 PassOwnPtr<MessagePortChannelArray> channels) | |
168 { | |
169 if (!thisPtr->client()) | |
170 return; | |
171 | |
172 WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0); | |
173 for (size_t i = 0; i < webChannels.size(); ++i) { | |
174 webChannels[i] = (*channels)[i]->channel()->webChannelRelease(); | |
175 webChannels[i]->setClient(0); | |
176 } | |
177 | |
178 thisPtr->client()->postMessageToWorkerObject(message, webChannels); | |
179 } | |
180 | |
181 void WebWorkerBase::postExceptionToWorkerObject(const String& errorMessage, | |
182 int lineNumber, | |
183 const String& sourceURL) | |
184 { | |
185 dispatchTaskToMainThread(createCallbackTask(&postExceptionTask, this, | |
186 errorMessage, lineNumber, | |
187 sourceURL)); | |
188 } | |
189 | |
190 void WebWorkerBase::postExceptionTask(ScriptExecutionContext* context, | |
191 WebWorkerBase* thisPtr, | |
192 const String& errorMessage, | |
193 int lineNumber, const String& sourceURL) | |
194 { | |
195 if (!thisPtr->commonClient()) | |
196 return; | |
197 | |
198 thisPtr->commonClient()->postExceptionToWorkerObject(errorMessage, | |
199 lineNumber, | |
200 sourceURL); | |
201 } | |
202 | |
203 void WebWorkerBase::postConsoleMessageToWorkerObject(MessageDestination destination, | |
204 MessageSource source, | |
205 MessageType type, | |
206 MessageLevel level, | |
207 const String& message, | |
208 int lineNumber, | |
209 const String& sourceURL) | |
210 { | |
211 dispatchTaskToMainThread(createCallbackTask(&postConsoleMessageTask, this, | |
212 static_cast<int>(destination), | |
213 static_cast<int>(source), | |
214 static_cast<int>(type), | |
215 static_cast<int>(level), | |
216 message, lineNumber, sourceURL)); | |
217 } | |
218 | |
219 void WebWorkerBase::postConsoleMessageTask(ScriptExecutionContext* context, | |
220 WebWorkerBase* thisPtr, | |
221 int destination, int source, | |
222 int type, int level, | |
223 const String& message, | |
224 int lineNumber, | |
225 const String& sourceURL) | |
226 { | |
227 if (!thisPtr->commonClient()) | |
228 return; | |
229 thisPtr->commonClient()->postConsoleMessageToWorkerObject(destination, source, | |
230 type, level, message, | |
231 lineNumber, sourceURL); | |
232 } | |
233 | |
234 void WebWorkerBase::confirmMessageFromWorkerObject(bool hasPendingActivity) | |
235 { | |
236 dispatchTaskToMainThread(createCallbackTask(&confirmMessageTask, this, | |
237 hasPendingActivity)); | |
238 } | |
239 | |
240 void WebWorkerBase::confirmMessageTask(ScriptExecutionContext* context, | |
241 WebWorkerBase* thisPtr, | |
242 bool hasPendingActivity) | |
243 { | |
244 if (!thisPtr->client()) | |
245 return; | |
246 thisPtr->client()->confirmMessageFromWorkerObject(hasPendingActivity); | |
247 } | |
248 | |
249 void WebWorkerBase::reportPendingActivity(bool hasPendingActivity) | |
250 { | |
251 dispatchTaskToMainThread(createCallbackTask(&reportPendingActivityTask, | |
252 this, hasPendingActivity)); | |
253 } | |
254 | |
255 void WebWorkerBase::reportPendingActivityTask(ScriptExecutionContext* context, | |
256 WebWorkerBase* thisPtr, | |
257 bool hasPendingActivity) | |
258 { | |
259 if (!thisPtr->client()) | |
260 return; | |
261 thisPtr->client()->reportPendingActivity(hasPendingActivity); | |
262 } | |
263 | |
264 void WebWorkerBase::workerContextClosed() | |
265 { | |
266 dispatchTaskToMainThread(createCallbackTask(&workerContextClosedTask, | |
267 this)); | |
268 } | |
269 | |
270 void WebWorkerBase::workerContextClosedTask(ScriptExecutionContext* context, | |
271 WebWorkerBase* thisPtr) | |
272 { | |
273 if (thisPtr->commonClient()) | |
274 thisPtr->commonClient()->workerContextClosed(); | |
275 } | |
276 | |
277 void WebWorkerBase::workerContextDestroyed() | |
278 { | |
279 dispatchTaskToMainThread(createCallbackTask(&workerContextDestroyedTask, | |
280 this)); | |
281 } | |
282 | |
283 void WebWorkerBase::workerContextDestroyedTask(ScriptExecutionContext* context, | |
284 WebWorkerBase* thisPtr) | |
285 { | |
286 if (thisPtr->commonClient()) | |
287 thisPtr->commonClient()->workerContextDestroyed(); | |
288 // The lifetime of this proxy is controlled by the worker context. | |
289 delete thisPtr; | |
290 } | |
291 | |
292 // WorkerLoaderProxy ----------------------------------------------------------- | |
293 | |
294 void WebWorkerBase::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task> task) | |
295 { | |
296 ASSERT(m_loadingDocument->isDocument()); | |
297 m_loadingDocument->postTask(task); | |
298 } | |
299 | |
300 void WebWorkerBase::postTaskForModeToWorkerContext( | |
301 PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode) | |
302 { | |
303 m_workerThread->runLoop().postTaskForMode(task, mode); | |
304 } | |
305 | |
306 #endif // ENABLE(WORKERS) | |
307 | |
308 } // namespace WebKit | |
OLD | NEW |