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

Side by Side Diff: sky/engine/core/script/dart_loader.cc

Issue 921903002: Add DartController and friends (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: More comment Created 5 years, 10 months 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 | « sky/engine/core/script/dart_loader.h ('k') | sky/engine/core/script/dom_dart_state.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 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sky/engine/config.h"
6 #include "sky/engine/core/script/dart_loader.h"
7
8 #include "base/callback.h"
9 #include "mojo/common/data_pipe_drainer.h"
10 #include "sky/engine/core/script/dart_dependency_catcher.h"
11 #include "sky/engine/core/script/dom_dart_state.h"
12 #include "sky/engine/platform/fetcher/MojoFetcher.h"
13 #include "sky/engine/platform/weborigin/KURL.h"
14 #include "sky/engine/tonic/dart_api_scope.h"
15 #include "sky/engine/tonic/dart_converter.h"
16 #include "sky/engine/tonic/dart_error.h"
17 #include "sky/engine/tonic/dart_isolate_scope.h"
18 #include "sky/engine/wtf/MainThread.h"
19
20 using mojo::common::DataPipeDrainer;
21
22 namespace blink {
23 namespace {
24
25 Dart_Handle CanonicalizeURL(DartState* state,
26 Dart_Handle library,
27 Dart_Handle url) {
28 String string = StringFromDart(url);
29 if (string.startsWith("dart:"))
30 return url;
31 // TODO(dart): Figure out how 'package:' should work in sky.
32 if (string.startsWith("package:")) {
33 string.replace("package:", "/gen/");
34 }
35 String library_url_string = StringFromDart(Dart_LibraryUrl(library));
36 KURL library_url = KURL(ParsedURLString, library_url_string);
37 KURL resolved_url = KURL(library_url, string);
38 return StringToDart(state, resolved_url.string());
39 }
40
41 } // namespace
42
43 // A DartLoader::Job represents a network load. It fetches data from the network
44 // and buffers the data in Vector. To cancel the job, delete this object.
45 class DartLoader::Job : public DartDependency,
46 public MojoFetcher::Client,
47 public DataPipeDrainer::Client {
48 public:
49 Job(DartLoader* loader, const KURL& url)
50 : loader_(loader), url_(url), fetcher_(this, url) {}
51
52 const KURL& url() const { return url_; }
53
54 protected:
55 DartLoader* loader_;
56 // TODO(abarth): Should we be using SharedBuffer to buffer the data?
57 Vector<uint8_t> buffer_;
58
59 private:
60 // MojoFetcher::Client
61 void OnReceivedResponse(mojo::URLResponsePtr response) override {
62 // TODO(abarth): Handle network errors.
63 drainer_ = adoptPtr(new DataPipeDrainer(this, response->body.Pass()));
64 }
65
66 // DataPipeDrainer::Client
67 void OnDataAvailable(const void* data, size_t num_bytes) override {
68 buffer_.append(static_cast<const uint8_t*>(data), num_bytes);
69 }
70 // Subclasses must implement OnDataComplete.
71
72 KURL url_;
73 MojoFetcher fetcher_;
74 OwnPtr<DataPipeDrainer> drainer_;
75 };
76
77 class DartLoader::ImportJob : public Job {
78 public:
79 using Job::Job;
80
81 private:
82 // DataPipeDrainer::Client
83 void OnDataComplete() override {
84 loader_->DidCompleteImportJob(this, buffer_);
85 }
86 };
87
88 class DartLoader::SourceJob : public Job {
89 public:
90 SourceJob(DartLoader* loader, const KURL& url, Dart_Handle library)
91 : Job(loader, url), library_(loader->dart_state(), library) {}
92
93 Dart_PersistentHandle library() const { return library_.value(); }
94
95 private:
96 // DataPipeDrainer::Client
97 void OnDataComplete() override {
98 loader_->DidCompleteSourceJob(this, buffer_);
99 }
100
101 DartPersistentValue library_;
102 };
103
104 // A DependencyWatcher represents a request to watch for when a given set of
105 // dependencies (either libraries or parts of libraries) have finished loading.
106 // When the dependencies are satisfied (including transitive dependencies), then
107 // the |callback| will be invoked.
108 class DartLoader::DependencyWatcher {
109 public:
110 DependencyWatcher(const HashSet<DartDependency*>& dependencies,
111 const base::Closure& callback)
112 : dependencies_(dependencies), callback_(callback) {
113 DCHECK(!dependencies_.isEmpty());
114 }
115
116 bool DidResolveDependency(DartDependency* resolved_dependency,
117 const HashSet<DartDependency*>& new_dependencies) {
118 const auto& it = dependencies_.find(resolved_dependency);
119 if (it == dependencies_.end())
120 return false;
121 dependencies_.remove(it);
122 for (const auto& dependency : new_dependencies)
123 dependencies_.add(dependency);
124 return dependencies_.isEmpty();
125 }
126
127 const base::Closure& callback() const { return callback_; }
128
129 private:
130 HashSet<DartDependency*> dependencies_;
131 base::Closure callback_;
132 };
133
134 // A WatcherSignaler is responsible for signaling DependencyWatchers when their
135 // dependencies resolve and for calling the DependencyWatcher's callback. We use
136 // a separate object of this task because we want to carefully manage when we
137 // call the callbacks, which can call into us again reentrantly.
138 //
139 // WatcherSignaler is designed to be placed on the stack as a RAII. After its
140 // destructor runs, we might have executed aribitrary script.
141 class DartLoader::WatcherSignaler {
142 public:
143 WatcherSignaler(DartLoader& loader, DartDependency* resolved_dependency)
144 : loader_(loader),
145 catcher_(adoptPtr(new DartDependencyCatcher(loader))),
146 resolved_dependency_(resolved_dependency) {}
147
148 ~WatcherSignaler() {
149 Vector<DependencyWatcher*> completed_watchers;
150 for (const auto& watcher : loader_.dependency_watchers_) {
151 if (watcher->DidResolveDependency(resolved_dependency_,
152 catcher_->dependencies()))
153 completed_watchers.append(watcher.get());
154 }
155
156 // Notice that we remove the dependency catcher and extract all the
157 // callbacks before running any of them. We don't want to be re-entered
158 // below the callbacks and end up in an inconsistent state.
159 catcher_.clear();
160 Vector<base::Closure> callbacks;
161 for (const auto& watcher : completed_watchers) {
162 callbacks.append(watcher->callback());
163 loader_.dependency_watchers_.remove(watcher);
164 }
165
166 // Finally, run all the callbacks while touching only data on the stack.
167 for (const auto& callback : callbacks)
168 callback.Run();
169 }
170
171 private:
172 DartLoader& loader_;
173 OwnPtr<DartDependencyCatcher> catcher_;
174 DartDependency* resolved_dependency_;
175 };
176
177 DartLoader::DartLoader(DartState* dart_state)
178 : dart_state_(dart_state->GetWeakPtr()), dependency_catcher_(nullptr) {
179 }
180
181 DartLoader::~DartLoader() {
182 }
183
184 Dart_Handle DartLoader::HandleLibraryTag(Dart_LibraryTag tag,
185 Dart_Handle library,
186 Dart_Handle url) {
187 DCHECK(Dart_IsLibrary(library));
188 DCHECK(Dart_IsString(url));
189 if (tag == Dart_kCanonicalizeUrl)
190 return CanonicalizeURL(DartState::Current(), library, url);
191 if (tag == Dart_kImportTag) {
192 CHECK(WTF::isMainThread());
193 return DOMDartState::Current()->loader().Import(library, url);
194 }
195 if (tag == Dart_kSourceTag) {
196 CHECK(WTF::isMainThread());
197 return DOMDartState::Current()->loader().Source(library, url);
198 }
199 DCHECK(false);
200 return Dart_NewApiError("Unknown library tag.");
201 }
202
203 void DartLoader::WaitForDependencies(
204 const HashSet<DartDependency*>& dependencies,
205 const base::Closure& callback) {
206 dependency_watchers_.add(
207 adoptPtr(new DependencyWatcher(dependencies, callback)));
208 }
209
210 Dart_Handle DartLoader::Import(Dart_Handle library, Dart_Handle url) {
211 KURL parsed_url(ParsedURLString, StringFromDart(url));
212 const auto& result = pending_libraries_.add(parsed_url.string(), nullptr);
213 if (result.isNewEntry) {
214 OwnPtr<Job> job = adoptPtr(new ImportJob(this, parsed_url));
215 result.storedValue->value = job.get();
216 jobs_.add(job.release());
217 }
218 if (dependency_catcher_)
219 dependency_catcher_->AddDependency(result.storedValue->value);
220 return Dart_True();
221 }
222
223 Dart_Handle DartLoader::Source(Dart_Handle library, Dart_Handle url) {
224 KURL parsed_url(ParsedURLString, StringFromDart(url));
225 OwnPtr<Job> job = adoptPtr(new SourceJob(this, parsed_url, library));
226 if (dependency_catcher_)
227 dependency_catcher_->AddDependency(job.get());
228 jobs_.add(job.release());
229 return Dart_True();
230 }
231
232 void DartLoader::DidCompleteImportJob(ImportJob* job,
233 const Vector<uint8_t>& buffer) {
234 DCHECK(dart_state_);
235 DartIsolateScope scope(dart_state_->isolate());
236 DartApiScope api_scope;
237
238 WatcherSignaler watcher_signaler(*this, job);
239
240 String url_string = job->url().string();
241 LogIfError(Dart_LoadLibrary(
242 StringToDart(dart_state_.get(), url_string),
243 Dart_NewStringFromUTF8(buffer.data(), buffer.size()), 0, 0));
244
245 pending_libraries_.remove(url_string);
246 jobs_.remove(job);
247 }
248
249 void DartLoader::DidCompleteSourceJob(SourceJob* job,
250 const Vector<uint8_t>& buffer) {
251 DCHECK(dart_state_);
252 DartIsolateScope scope(dart_state_->isolate());
253 DartApiScope api_scope;
254
255 WatcherSignaler watcher_signaler(*this, job);
256
257 LogIfError(Dart_LoadSource(
258 Dart_HandleFromPersistent(job->library()),
259 StringToDart(dart_state_.get(), job->url().string()),
260 Dart_NewStringFromUTF8(buffer.data(), buffer.size()), 0, 0));
261
262 jobs_.remove(job);
263 }
264
265 } // namespace blink
OLDNEW
« no previous file with comments | « sky/engine/core/script/dart_loader.h ('k') | sky/engine/core/script/dom_dart_state.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698