OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009, Google Inc. | |
2 // 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 #include "config.h" | |
31 #include "DartApplicationLoader.h" | |
32 | |
33 #include "CachedResourceClient.h" | |
34 #include "CachedResourceLoader.h" | |
35 #include "DOMWindow.h" | |
36 #include "DartDOMWrapper.h" | |
37 #include "DartIsolateState.h" | |
38 #include "DartUtilities.h" | |
39 #include "Document.h" | |
40 #include "Frame.h" | |
41 #include "ScriptCallStack.h" | |
42 #include "ScriptSourceCode.h" | |
43 | |
44 #include <dart_api.h> | |
45 | |
46 namespace WebCore { | |
47 | |
48 DartApplicationLoader::DartApplicationLoader(Document* document) | |
49 : m_document(document) | |
50 , m_libraryUrl() | |
51 , m_importedLibraries() | |
52 , m_importersForSource() | |
53 , m_sources() | |
54 , m_mainScriptHasBeenLoaded(false) | |
55 { | |
56 } | |
57 | |
58 void DartApplicationLoader::load(const String& url, const String& source) | |
59 { | |
60 DartApiScope dartApiScope; | |
61 | |
62 if (m_importedLibraries.isEmpty() && m_importersForSource.isEmpty()) | |
63 loadScript(url, source); | |
64 else { | |
65 if (m_importedLibraries.contains(url)) { | |
66 loadLibrary(url, source); | |
67 m_importedLibraries.remove(url); | |
68 } | |
69 | |
70 if (m_importersForSource.contains(url)) { | |
71 loadSource(url, source); | |
72 m_importersForSource.remove(url); | |
73 } | |
74 } | |
75 | |
76 m_sources.add(url, source); | |
77 | |
78 if (m_importedLibraries.isEmpty() && m_importersForSource.isEmpty() && m_mai
nScriptHasBeenLoaded) | |
79 callEntryPoint(); | |
80 } | |
81 | |
82 void DartApplicationLoader::importBuiltinLibrary(const String& url, const String
& source) | |
83 { | |
84 Dart_Handle result = Dart_LoadLibrary(DartUtilities::stringToDartString(url)
, DartUtilities::stringToDartString(source)); | |
85 if (Dart_IsError(result)) { | |
86 DartUtilities::reportProblem(m_document, result); | |
87 return; | |
88 } | |
89 m_sources.add(url, source); | |
90 } | |
91 | |
92 IsolateToDartApplicationLoaderMap& isolateToDartApplicationLoaderMap() | |
93 { | |
94 DEFINE_STATIC_LOCAL(IsolateToDartApplicationLoaderMap, map, ()); | |
95 return map; | |
96 } | |
97 | |
98 static DartApplicationLoader* currentAppLoader() | |
99 { | |
100 IsolateToDartApplicationLoaderMap::iterator it = isolateToDartApplicationLoa
derMap().find(Dart_CurrentIsolate()); | |
101 ASSERT(it != isolateToDartApplicationLoaderMap().end()); | |
102 return it->second; | |
103 } | |
104 | |
105 template <class Loader> | |
106 class ScriptLoader { | |
107 public: | |
108 static void loadScript(const String& url, const String& source, ScriptExecut
ionContext* context) | |
109 { | |
110 Dart_Handle result = Dart_LoadScript( | |
111 DartUtilities::stringToDartString(url), | |
112 DartUtilities::stringToDartString(source), | |
113 &handler); | |
114 if (Dart_IsError(result)) | |
115 DartUtilities::reportProblem(context, result); | |
116 } | |
117 | |
118 private: | |
119 static Dart_Handle handler(Dart_LibraryTag tag, Dart_Handle library, Dart_Ha
ndle urlHandle) | |
120 { | |
121 ASSERT(Dart_IsLibrary(library)); | |
122 | |
123 String url = DartUtilities::dartStringToString(urlHandle); | |
124 | |
125 Dart_Handle libraryURLHandle = Dart_LibraryUrl(library); | |
126 ASSERT(!Dart_IsError(libraryURLHandle)); | |
127 const String libraryURL = DartUtilities::dartStringToString(libraryURLHa
ndle); | |
128 | |
129 if (tag == kCanonicalizeUrl) { | |
130 const KURL canonical = KURL(KURL(KURL(), libraryURL), url); | |
131 return DartUtilities::stringToDartString(canonical.string()); | |
132 } | |
133 | |
134 return Loader::load(tag, library, libraryURL, url); | |
135 } | |
136 }; | |
137 | |
138 struct InitialLoader { | |
139 static Dart_Handle load(Dart_LibraryTag tag, Dart_Handle library, const Stri
ng& libraryUrl, const String& importedUrl) | |
140 { | |
141 currentAppLoader()->triggerImport(libraryUrl, importedUrl, tag); | |
142 return Dart_NewBoolean(true); | |
143 } | |
144 }; | |
145 | |
146 void DartApplicationLoader::loadScript(const String& url, const String& source) | |
147 { | |
148 ASSERT(m_importedLibraries.isEmpty()); | |
149 ASSERT(m_importersForSource.isEmpty()); | |
150 m_libraryUrl = url; | |
151 ScriptLoader<InitialLoader>::loadScript(url, source, m_document); | |
152 m_mainScriptHasBeenLoaded = true; | |
153 } | |
154 | |
155 void DartApplicationLoader::loadSource(const String& url, const String& source) | |
156 { | |
157 ASSERT(m_importersForSource.contains(url)); | |
158 const UrlSet* importers = m_importersForSource.find(url)->second; | |
159 Dart_Handle dartUrl = DartUtilities::stringToDartString(url); | |
160 Dart_Handle dartSource = DartUtilities::stringToDartString(source); | |
161 for (UrlSet::iterator iter = importers->begin(); iter != importers->end(); +
+iter) { | |
162 Dart_Handle library = Dart_LookupLibrary(DartUtilities::stringToDartStri
ng(*iter)); | |
163 if (Dart_IsError(library)) { | |
164 DartUtilities::reportProblem(m_document, library); | |
165 return; | |
166 } | |
167 Dart_Handle result = Dart_LoadSource(library, dartUrl, dartSource); | |
168 if (Dart_IsError(result)) { | |
169 DartUtilities::reportProblem(m_document, result); | |
170 return; | |
171 } | |
172 } | |
173 } | |
174 | |
175 void DartApplicationLoader::loadLibrary(const String& url, const String& source) | |
176 { | |
177 ASSERT(m_importedLibraries.contains(url)); | |
178 Dart_Handle result = Dart_LoadLibrary(DartUtilities::stringToDartString(url)
, DartUtilities::stringToDartString(source)); | |
179 if (Dart_IsError(result)) | |
180 DartUtilities::reportProblem(m_document, result); | |
181 } | |
182 | |
183 void DartApplicationLoader::callEntryPoint() | |
184 { | |
185 ASSERT(m_document->readyState() != "loading"); | |
186 Dart_Handle result = Dart_InvokeStatic(topLevelLibrary(), Dart_NewString("")
, Dart_NewString("main"), 0, 0); | |
187 if (Dart_IsError(result)) | |
188 DartUtilities::reportProblem(m_document, result); | |
189 } | |
190 | |
191 Dart_Handle DartApplicationLoader::topLevelLibrary() | |
192 { | |
193 Dart_Handle library = Dart_LookupLibrary(DartUtilities::stringToDartString(m
_libraryUrl)); | |
194 ASSERT(!Dart_IsError(library)); | |
195 return library; | |
196 } | |
197 | |
198 Dart_Handle DartApplicationLoader::domLibrary() | |
199 { | |
200 Dart_Handle library = Dart_LookupLibrary(Dart_NewString(DartUtilities::domLi
braryName)); | |
201 ASSERT(!Dart_IsError(library)); | |
202 return library; | |
203 } | |
204 | |
205 class ScriptLoadCallback : public CachedResourceClient { | |
206 public: | |
207 ScriptLoadCallback(DartApplicationLoader* loader, CachedScript* cachedScript
, Dart_Isolate isolate) | |
208 : m_loader(loader) | |
209 , m_cachedScript(cachedScript) | |
210 , m_isolate(isolate) | |
211 { | |
212 } | |
213 | |
214 virtual void notifyFinished(CachedResource* cachedResource) | |
215 { | |
216 ASSERT(cachedResource->type() == CachedResource::Script); | |
217 ASSERT(cachedResource == m_cachedScript.get()); | |
218 ASSERT(WTF::isMainThread()); | |
219 | |
220 if (cachedResource->errorOccurred()) | |
221 m_loader->scriptLoadError(cachedResource->url()); | |
222 else if (cachedResource->wasCanceled()) { | |
223 // FIXME: shall we let VM know, so it can inform application some of
its | |
224 // resources cannot be loaded? | |
225 } else { | |
226 // FIXME: we can get rid of imported libs and sources map. | |
227 ScriptSourceCode sourceCode(m_cachedScript.get()); | |
228 DartIsolateState::Scope scope(m_isolate); | |
229 m_loader->load(sourceCode.url(), sourceCode.source()); | |
230 } | |
231 | |
232 m_cachedScript->removeClient(this); | |
233 delete this; | |
234 } | |
235 | |
236 private: | |
237 RefPtr<DartApplicationLoader> m_loader; | |
238 CachedResourceHandle<CachedScript> m_cachedScript; | |
239 Dart_Isolate m_isolate; | |
240 }; | |
241 | |
242 void DartApplicationLoader::triggerImport(const String& libraryUrl, const String
& importedUrl, Dart_LibraryTag tag) | |
243 { | |
244 ASSERT(importedUrl != "dart:dom"); | |
245 ASSERT(importedUrl != "dart:json"); | |
246 ASSERT(importedUrl != "dart:html"); | |
247 ASSERT(importedUrl != "dart:htmlimpl"); | |
248 | |
249 // Record the importer. | |
250 if (tag == kImportTag) | |
251 m_importedLibraries.add(importedUrl); | |
252 else if (tag == kSourceTag) | |
253 add(m_importersForSource, importedUrl, libraryUrl); | |
254 else | |
255 ASSERT_NOT_REACHED(); | |
256 | |
257 loadScriptResource(importedUrl); | |
258 } | |
259 | |
260 void DartApplicationLoader::loadScriptResource(const String& url) | |
261 { | |
262 // Request loading of script dependencies. | |
263 CachedResourceLoader* loader = m_document->cachedResourceLoader(); | |
264 ResourceRequest request(m_document->completeURL(url)); | |
265 // FIXME: what about charset for this script, maybe use charset of initial s
cript tag? | |
266 CachedScript* cachedScript = loader->requestScript(request, "utf-8"); | |
267 if (cachedScript) | |
268 cachedScript->addClient(new ScriptLoadCallback(this, cachedScript, Dart_
CurrentIsolate())); | |
269 else | |
270 scriptLoadError(KURL(KURL(), url)); | |
271 } | |
272 | |
273 void DartApplicationLoader::scriptLoadError(const KURL& url) | |
274 { | |
275 // FIXME: source file info (must be captured when requesting resource). | |
276 String sourceFile = "FIXME"; | |
277 // FIXME: line number info (must be captured when requesting resource). | |
278 int lineNumber = 0; | |
279 // FIXME: call stack info (must be captured when requesting resource). | |
280 RefPtr<ScriptCallStack> callStack; | |
281 String errorMessage = "Cannot load Dart script " + url.string(); | |
282 m_document->reportException(errorMessage, lineNumber, sourceFile, callStack)
; | |
283 // FIXME: shall we let VM know, so it can inform application some of its | |
284 // resources cannot be loaded? | |
285 } | |
286 | |
287 Dart_Handle DartApplicationLoader::reinject(Dart_Handle library, const String& l
ibraryUrl, const String& importedUrl, Dart_LibraryTag tag) | |
288 { | |
289 ASSERT(m_sources.contains(importedUrl)); | |
290 const String& source = m_sources.get(importedUrl); | |
291 | |
292 Dart_Handle dartSource = DartUtilities::stringToDartString(source); | |
293 if (tag == kImportTag) { | |
294 Dart_Handle result = Dart_LoadLibrary(DartUtilities::stringToDartString(
importedUrl), dartSource); | |
295 if (Dart_IsError(result)) | |
296 return result; | |
297 } else if (tag == kSourceTag) { | |
298 Dart_Handle result = Dart_LoadSource(library, DartUtilities::stringToDar
tString(importedUrl), dartSource); | |
299 if (Dart_IsError(result)) | |
300 return result; | |
301 } else | |
302 ASSERT_NOT_REACHED(); | |
303 | |
304 return Dart_NewBoolean(true); | |
305 } | |
306 | |
307 void DartApplicationLoader::add(UrlMultiMap& map, const String& key, const Strin
g& value) | |
308 { | |
309 // We should never have a self dependence. | |
310 ASSERT(key != value); | |
311 UrlMultiMap::iterator iter = map.find(key); | |
312 if (iter == map.end()) | |
313 iter = map.add(key, new UrlSet()).first; | |
314 UrlSet* set = iter->second; | |
315 set->add(value); | |
316 } | |
317 | |
318 struct ReinjectLoader { | |
319 static Dart_Handle load(Dart_LibraryTag tag, Dart_Handle library, const Stri
ng& libraryUrl, const String& importedUrl) | |
320 { | |
321 return currentAppLoader()->reinject(library, libraryUrl, importedUrl, ta
g); | |
322 } | |
323 }; | |
324 | |
325 void DartApplicationLoader::reinjectSources() | |
326 { | |
327 ASSERT(!isLoadingMainIsolate()); | |
328 | |
329 // FIXME: propagate flags as well. | |
330 | |
331 // Set proper dart loader for child isolate. | |
332 isolateToDartApplicationLoaderMap().set(Dart_CurrentIsolate(), this); | |
333 | |
334 ASSERT(m_sources.contains(m_libraryUrl)); | |
335 ScriptLoader<ReinjectLoader>::loadScript(m_libraryUrl, m_sources.get(m_libra
ryUrl), m_document); | |
336 } | |
337 | |
338 } | |
OLD | NEW |