OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrCaps.h" | 8 #include "GrCaps.h" |
9 #include "GrContextFactory.h" | 9 #include "GrContextFactory.h" |
10 #include "SkCanvas.h" | 10 #include "SkCanvas.h" |
11 #include "SkCommandLineFlags.h" | 11 #include "SkCommandLineFlags.h" |
12 #include "SkDebugCanvas.h" | |
12 #include "SkJSONCanvas.h" | 13 #include "SkJSONCanvas.h" |
13 #include "SkPicture.h" | 14 #include "SkPicture.h" |
14 #include "SkStream.h" | 15 #include "SkStream.h" |
15 #include "SkSurface.h" | 16 #include "SkSurface.h" |
16 | 17 |
17 #include <sys/socket.h> | 18 #include <sys/socket.h> |
18 #include <microhttpd.h> | 19 #include <microhttpd.h> |
19 | 20 |
20 // To get image decoders linked in we have to do the below magic | 21 // To get image decoders linked in we have to do the below magic |
21 #include "SkForceLinking.h" | 22 #include "SkForceLinking.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 | 55 |
55 struct UploadContext { | 56 struct UploadContext { |
56 SkDynamicMemoryWStream fStream; | 57 SkDynamicMemoryWStream fStream; |
57 MHD_PostProcessor* fPostProcessor; | 58 MHD_PostProcessor* fPostProcessor; |
58 MHD_Connection* connection; | 59 MHD_Connection* connection; |
59 }; | 60 }; |
60 | 61 |
61 struct Request { | 62 struct Request { |
62 Request() : fUploadContext(nullptr) {} | 63 Request() : fUploadContext(nullptr) {} |
63 UploadContext* fUploadContext; | 64 UploadContext* fUploadContext; |
64 SkAutoTUnref<SkData> fPNG; | |
65 SkAutoTUnref<SkPicture> fPicture; | 65 SkAutoTUnref<SkPicture> fPicture; |
66 SkAutoTUnref<SkDebugCanvas> fDebugCanvas; | |
66 }; | 67 }; |
67 | 68 |
68 // TODO factor this out into functions, also handle CPU path | 69 // TODO factor this out into functions, also handle CPU path |
69 bool setupAndDrawToCanvas(Request* request, SkString* error) { | 70 SkSurface* setupSurface(GrContextFactory* factory) { |
70 GrContextOptions grContextOpts; | |
71 SkAutoTDelete<GrContextFactory> factory(new GrContextFactory(grContextOpts)) ; | |
72 | |
73 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType, | 71 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType, |
74 GrContextFactory::kNone_GLContextOptions); | 72 GrContextFactory::kNone_GLContextOptions); |
75 int maxRTSize = context->caps()->maxRenderTargetSize(); | 73 int maxRTSize = context->caps()->maxRenderTargetSize(); |
76 SkImageInfo info = SkImageInfo::Make(SkTMin(kImageWidth, maxRTSize), | 74 SkImageInfo info = SkImageInfo::Make(SkTMin(kImageWidth, maxRTSize), |
77 SkTMin(kImageHeight, maxRTSize), | 75 SkTMin(kImageHeight, maxRTSize), |
78 kN32_SkColorType, kPremul_SkAlphaType); | 76 kN32_SkColorType, kPremul_SkAlphaType); |
79 uint32_t flags = 0; | 77 uint32_t flags = 0; |
80 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType); | 78 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType); |
81 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(context, | 79 SkSurface* surface = SkSurface::NewRenderTarget(context, SkSurface::kNo_Budg eted, info, 0, |
82 SkSurface::kNo_Bu dgeted, info, | 80 &props); |
83 0, &props)); | 81 SkASSERT(surface); |
84 SkASSERT(surface.get()); | |
85 | 82 |
86 SkGLContext* gl = factory->getContextInfo(GrContextFactory::kNative_GLContex tType, | 83 SkGLContext* gl = factory->getContextInfo(GrContextFactory::kNative_GLContex tType, |
87 GrContextFactory::kNone_GLContextO ptions).fGLContext; | 84 GrContextFactory::kNone_GLContextO ptions).fGLContext; |
88 gl->makeCurrent(); | 85 gl->makeCurrent(); |
86 return surface; | |
87 } | |
89 | 88 |
90 // draw | 89 SkData* writeCanvasToPng(SkCanvas* canvas) { |
91 request->fPicture.reset( | |
92 SkPicture::CreateFromStream(request->fUploadContext->fStream.detachAsStr eam())); | |
93 if (!request->fPicture.get()) { | |
94 error->appendf("Could not create picture from stream.\n"); | |
95 return false; | |
96 } | |
97 | |
98 SkCanvas* canvas = surface->getCanvas(); | |
99 canvas->drawPicture(request->fPicture); | |
100 | |
101 // capture pixels | 90 // capture pixels |
102 SkBitmap bmp; | 91 SkBitmap bmp; |
103 bmp.setInfo(canvas->imageInfo()); | 92 bmp.setInfo(canvas->imageInfo()); |
104 if (!canvas->readPixels(&bmp, 0, 0)) { | 93 if (!canvas->readPixels(&bmp, 0, 0)) { |
105 error->appendf("Can't read canvas pixels.\n"); | 94 fprintf(stderr, "Can't read pixels\n"); |
106 return false; | 95 return nullptr; |
107 } | 96 } |
108 | 97 |
109 // write to png | 98 // write to png |
110 request->fPNG.reset(SkImageEncoder::EncodeData(bmp, SkImageEncoder::kPNG_Typ e, 100)); | 99 SkData* png = SkImageEncoder::EncodeData(bmp, SkImageEncoder::kPNG_Type, 100 ); |
111 if (!request->fPNG) { | 100 if (!png) { |
112 error->appendf("Can't encode a PNG.\n"); | 101 fprintf(stderr, "Can't encode to png\n"); |
113 return false; | 102 return nullptr; |
114 } | 103 } |
115 return true; | 104 return png; |
105 } | |
106 | |
107 SkData* setupAndDrawToCanvasReturnPng(SkDebugCanvas* debugCanvas, int n) { | |
108 GrContextOptions grContextOpts; | |
109 SkAutoTDelete<GrContextFactory> factory(new GrContextFactory(grContextOpts)) ; | |
110 SkAutoTUnref<SkSurface> surface(setupSurface(factory.get())); | |
111 | |
112 SkASSERT(debugCanvas); | |
113 SkCanvas* canvas = surface->getCanvas(); | |
114 debugCanvas->drawTo(canvas, n); | |
115 return writeCanvasToPng(canvas); | |
116 } | 116 } |
117 | 117 |
118 static const size_t kBufferSize = 1024; | 118 static const size_t kBufferSize = 1024; |
119 | 119 |
120 static int process_upload_data(void* cls, enum MHD_ValueKind kind, | 120 static int process_upload_data(void* cls, enum MHD_ValueKind kind, |
121 const char* key, const char* filename, | 121 const char* key, const char* filename, |
122 const char* content_type, const char* transfer_en coding, | 122 const char* content_type, const char* transfer_en coding, |
123 const char* data, uint64_t off, size_t size) { | 123 const char* data, uint64_t off, size_t size) { |
124 struct UploadContext* uc = reinterpret_cast<UploadContext*>(cls); | 124 struct UploadContext* uc = reinterpret_cast<UploadContext*>(cls); |
125 | 125 |
126 if (0 != size) { | 126 if (0 != size) { |
127 uc->fStream.write(data, size); | 127 uc->fStream.write(data, size); |
128 } | 128 } |
129 return MHD_YES; | 129 return MHD_YES; |
130 } | 130 } |
131 | 131 |
132 static int SendData(MHD_Connection* connection, const SkData* data, const char* type) { | 132 static int SendData(MHD_Connection* connection, const SkData* data, const char* type) { |
133 MHD_Response* response = MHD_create_response_from_buffer(data->size(), | 133 MHD_Response* response = MHD_create_response_from_buffer(data->size(), |
134 const_cast<void*>(d ata->data()), | 134 const_cast<void*>(d ata->data()), |
135 MHD_RESPMEM_MUST_CO PY); | 135 MHD_RESPMEM_MUST_CO PY); |
136 MHD_add_response_header(response, "Content-Type", type); | 136 MHD_add_response_header(response, "Content-Type", type); |
137 | 137 |
138 int ret = MHD_queue_response(connection, MHD_HTTP_OK, response); | 138 int ret = MHD_queue_response(connection, MHD_HTTP_OK, response); |
139 MHD_destroy_response(response); | 139 MHD_destroy_response(response); |
140 return ret; | 140 return ret; |
141 } | 141 } |
142 | 142 |
143 static int SendJSON(MHD_Connection* connection, SkPicture* picture) { | 143 static int SendJSON(MHD_Connection* connection, SkDebugCanvas* debugCanvas, int n) { |
144 SkDynamicMemoryWStream stream; | 144 SkDynamicMemoryWStream stream; |
145 SkAutoTUnref<SkJSONCanvas> jsonCanvas(new SkJSONCanvas(kImageWidth, kImageHe ight, stream)); | 145 SkAutoTUnref<SkJSONCanvas> jsonCanvas(new SkJSONCanvas(kImageWidth, kImageHe ight, stream)); |
146 jsonCanvas->drawPicture(picture); | 146 debugCanvas->drawTo(jsonCanvas, n); |
147 jsonCanvas->finish(); | 147 jsonCanvas->finish(); |
148 | 148 |
149 SkAutoTUnref<SkData> data(stream.copyToData()); | 149 SkAutoTUnref<SkData> data(stream.copyToData()); |
150 return SendData(connection, data, "application/json"); | 150 return SendData(connection, data, "application/json"); |
151 } | 151 } |
152 | 152 |
153 static int SendTemplate(MHD_Connection* connection, bool redirect = false, | 153 static int SendTemplate(MHD_Connection* connection, bool redirect = false, |
154 const char* redirectUrl = nullptr) { | 154 const char* redirectUrl = nullptr) { |
155 SkString debuggerTemplate = generateTemplate(SkString(FLAGS_source[0])); | 155 SkString debuggerTemplate = generateTemplate(SkString(FLAGS_source[0])); |
156 | 156 |
(...skipping 13 matching lines...) Expand all Loading... | |
170 int ret = MHD_queue_response(connection, status, response); | 170 int ret = MHD_queue_response(connection, status, response); |
171 MHD_destroy_response(response); | 171 MHD_destroy_response(response); |
172 return ret; | 172 return ret; |
173 } | 173 } |
174 | 174 |
175 class UrlHandler { | 175 class UrlHandler { |
176 public: | 176 public: |
177 virtual ~UrlHandler() {} | 177 virtual ~UrlHandler() {} |
178 virtual bool canHandle(const char* method, const char* url) = 0; | 178 virtual bool canHandle(const char* method, const char* url) = 0; |
179 virtual int handle(Request* request, MHD_Connection* connection, | 179 virtual int handle(Request* request, MHD_Connection* connection, |
180 const char* url, const char* method, | |
180 const char* upload_data, size_t* upload_data_size) = 0; | 181 const char* upload_data, size_t* upload_data_size) = 0; |
181 }; | 182 }; |
182 | 183 |
183 class InfoHandler : public UrlHandler { | 184 class InfoHandler : public UrlHandler { |
184 public: | 185 public: |
185 bool canHandle(const char* method, const char* url) override { | 186 bool canHandle(const char* method, const char* url) override { |
186 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) && | 187 const char* kBasePath = "/cmd"; |
187 0 == strcmp(url, "/cmd"); | 188 return 0 == strncmp(url, kBasePath, strlen(kBasePath)); |
188 } | 189 } |
189 | 190 |
190 int handle(Request* request, MHD_Connection* connection, | 191 int handle(Request* request, MHD_Connection* connection, |
192 const char* url, const char* method, | |
191 const char* upload_data, size_t* upload_data_size) override { | 193 const char* upload_data, size_t* upload_data_size) override { |
192 if (request->fPicture.get()) { | 194 SkTArray<SkString> commands; |
193 return SendJSON(connection, request->fPicture); | 195 SkStrSplit(url, "/", &commands); |
196 | |
197 if (!request->fPicture.get() || commands.count() > 3) { | |
198 return MHD_NO; | |
194 } | 199 } |
200 | |
201 // /cmd or /cmd/N or /cmd/N/[0|1] | |
202 if (commands.count() == 1 && 0 == strcmp(method, MHD_HTTP_METHOD_GET)) { | |
203 int n = request->fDebugCanvas->getSize() - 1; | |
204 return SendJSON(connection, request->fDebugCanvas, n); | |
205 } | |
206 | |
207 // /cmd/N, for now only delete supported | |
208 if (commands.count() == 2 && 0 == strcmp(method, MHD_HTTP_METHOD_DELETE) ) { | |
209 int n; | |
210 sscanf(commands[1].c_str(), "%d", &n); | |
211 request->fDebugCanvas->deleteDrawCommandAt(n); | |
212 return MHD_YES; | |
213 } | |
214 | |
215 // /cmd/N/[0|1] | |
216 if (commands.count() == 3 && 0 == strcmp(method, MHD_HTTP_METHOD_POST)) { | |
217 int n, toggle; | |
218 sscanf(commands[1].c_str(), "%d", &n); | |
219 sscanf(commands[2].c_str(), "%d", &toggle); | |
220 request->fDebugCanvas->toggleCommand(n, toggle); | |
221 return MHD_YES; | |
222 } | |
223 | |
195 return MHD_NO; | 224 return MHD_NO; |
196 } | 225 } |
197 }; | 226 }; |
198 | 227 |
199 class ImgHandler : public UrlHandler { | 228 class ImgHandler : public UrlHandler { |
200 public: | 229 public: |
201 bool canHandle(const char* method, const char* url) override { | 230 bool canHandle(const char* method, const char* url) override { |
202 static const char* kBasePath = "/img"; | 231 static const char* kBasePath = "/img"; |
203 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) && | 232 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) && |
204 0 == strncmp(url, kBasePath, strlen(kBasePath)); | 233 0 == strncmp(url, kBasePath, strlen(kBasePath)); |
205 } | 234 } |
206 | 235 |
207 int handle(Request* request, MHD_Connection* connection, | 236 int handle(Request* request, MHD_Connection* connection, |
237 const char* url, const char* method, | |
208 const char* upload_data, size_t* upload_data_size) override { | 238 const char* upload_data, size_t* upload_data_size) override { |
209 if (request->fPNG.get()) { | 239 SkTArray<SkString> commands; |
210 SkData* data = request->fPNG.get(); | 240 SkStrSplit(url, "/", &commands); |
jcgregorio
2016/02/02 18:08:13
Need to split off the trailing ?blahblahblah first
| |
211 return SendData(connection, data, "image/png"); | 241 |
242 if (!request->fPicture.get() || commands.count() > 2) { | |
243 return MHD_NO; | |
212 } | 244 } |
213 | 245 |
214 return MHD_NO; | 246 int n; |
247 // /img or /img/N | |
248 if (commands.count() == 1) { | |
249 n = request->fDebugCanvas->getSize() - 1; | |
250 } else { | |
251 sscanf(commands[1].c_str(), "%d", &n); | |
252 } | |
253 | |
254 SkAutoTUnref<SkData> data(setupAndDrawToCanvasReturnPng(request->fDebugC anvas, n)); | |
255 return SendData(connection, data, "image/png"); | |
215 } | 256 } |
216 }; | 257 }; |
217 | 258 |
218 class PostHandler : public UrlHandler { | 259 class PostHandler : public UrlHandler { |
219 public: | 260 public: |
220 bool canHandle(const char* method, const char* url) override { | 261 bool canHandle(const char* method, const char* url) override { |
221 return 0 == strcmp(method, MHD_HTTP_METHOD_POST) && | 262 return 0 == strcmp(method, MHD_HTTP_METHOD_POST) && |
222 0 == strcmp(url, "/new"); | 263 0 == strcmp(url, "/new"); |
223 } | 264 } |
224 | 265 |
225 int handle(Request* request, MHD_Connection* connection, | 266 int handle(Request* request, MHD_Connection* connection, |
267 const char* url, const char* method, | |
226 const char* upload_data, size_t* upload_data_size) override { | 268 const char* upload_data, size_t* upload_data_size) override { |
227 UploadContext* uc = request->fUploadContext; | 269 UploadContext* uc = request->fUploadContext; |
228 | 270 |
229 // New connection | 271 // New connection |
230 if (!uc) { | 272 if (!uc) { |
231 // TODO make this a method on request | 273 // TODO make this a method on request |
232 uc = new UploadContext; | 274 uc = new UploadContext; |
233 uc->connection = connection; | 275 uc->connection = connection; |
234 uc->fPostProcessor = MHD_create_post_processor(connection, kBufferSi ze, | 276 uc->fPostProcessor = MHD_create_post_processor(connection, kBufferSi ze, |
235 &process_upload_data, uc); | 277 &process_upload_data, uc); |
236 SkASSERT(uc->fPostProcessor); | 278 SkASSERT(uc->fPostProcessor); |
237 | 279 |
238 request->fUploadContext = uc; | 280 request->fUploadContext = uc; |
239 return MHD_YES; | 281 return MHD_YES; |
240 } | 282 } |
241 | 283 |
242 // in process upload | 284 // in process upload |
243 if (0 != *upload_data_size) { | 285 if (0 != *upload_data_size) { |
244 SkASSERT(uc->fPostProcessor); | 286 SkASSERT(uc->fPostProcessor); |
245 MHD_post_process(uc->fPostProcessor, upload_data, *upload_data_size) ; | 287 MHD_post_process(uc->fPostProcessor, upload_data, *upload_data_size) ; |
246 *upload_data_size = 0; | 288 *upload_data_size = 0; |
247 return MHD_YES; | 289 return MHD_YES; |
248 } | 290 } |
249 | 291 |
250 // end of upload | 292 // end of upload |
251 MHD_destroy_post_processor(uc->fPostProcessor); | 293 MHD_destroy_post_processor(uc->fPostProcessor); |
252 uc->fPostProcessor = nullptr; | 294 uc->fPostProcessor = nullptr; |
253 | 295 |
254 // TODO response | 296 // parse picture from stream |
255 SkString error; | 297 request->fPicture.reset( |
256 if (!setupAndDrawToCanvas(request, &error)) { | 298 SkPicture::CreateFromStream(request->fUploadContext->fStream.detachA sStream())); |
257 // TODO send error | 299 if (!request->fPicture.get()) { |
258 return MHD_YES; | 300 fprintf(stderr, "Could not create picture from stream.\n"); |
301 return MHD_NO; | |
259 } | 302 } |
260 | 303 |
304 // pour picture into debug canvas | |
305 request->fDebugCanvas.reset(new SkDebugCanvas(kImageWidth, kImageHeight) ); | |
306 request->fDebugCanvas->drawPicture(request->fPicture); | |
307 | |
261 // clear upload context | 308 // clear upload context |
262 delete request->fUploadContext; | 309 delete request->fUploadContext; |
263 request->fUploadContext = nullptr; | 310 request->fUploadContext = nullptr; |
264 | 311 |
265 return SendTemplate(connection, true, "/"); | 312 return SendTemplate(connection, true, "/"); |
266 } | 313 } |
267 }; | 314 }; |
268 | 315 |
269 class RootHandler : public UrlHandler { | 316 class RootHandler : public UrlHandler { |
270 public: | 317 public: |
271 bool canHandle(const char* method, const char* url) override { | 318 bool canHandle(const char* method, const char* url) override { |
272 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) && | 319 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) && |
273 0 == strcmp(url, "/"); | 320 0 == strcmp(url, "/"); |
274 } | 321 } |
275 | 322 |
276 int handle(Request* request, MHD_Connection* connection, | 323 int handle(Request* request, MHD_Connection* connection, |
324 const char* url, const char* method, | |
277 const char* upload_data, size_t* upload_data_size) override { | 325 const char* upload_data, size_t* upload_data_size) override { |
278 return SendTemplate(connection); | 326 return SendTemplate(connection); |
279 } | 327 } |
280 }; | 328 }; |
281 | 329 |
282 class UrlManager { | 330 class UrlManager { |
283 public: | 331 public: |
284 UrlManager() { | 332 UrlManager() { |
285 // Register handlers | 333 // Register handlers |
286 fHandlers.push_back(new RootHandler); | 334 fHandlers.push_back(new RootHandler); |
287 fHandlers.push_back(new PostHandler); | 335 fHandlers.push_back(new PostHandler); |
288 fHandlers.push_back(new ImgHandler); | 336 fHandlers.push_back(new ImgHandler); |
289 fHandlers.push_back(new InfoHandler); | 337 fHandlers.push_back(new InfoHandler); |
290 } | 338 } |
291 | 339 |
292 ~UrlManager() { | 340 ~UrlManager() { |
293 for (int i = 0; i < fHandlers.count(); i++) { delete fHandlers[i]; } | 341 for (int i = 0; i < fHandlers.count(); i++) { delete fHandlers[i]; } |
294 } | 342 } |
295 | 343 |
296 // This is clearly not efficient for a large number of urls and handlers | 344 // This is clearly not efficient for a large number of urls and handlers |
297 int invoke(Request* request, MHD_Connection* connection, const char* url, co nst char* method, | 345 int invoke(Request* request, MHD_Connection* connection, const char* url, co nst char* method, |
298 const char* upload_data, size_t* upload_data_size) const { | 346 const char* upload_data, size_t* upload_data_size) const { |
299 for (int i = 0; i < fHandlers.count(); i++) { | 347 for (int i = 0; i < fHandlers.count(); i++) { |
300 if (fHandlers[i]->canHandle(method, url)) { | 348 if (fHandlers[i]->canHandle(method, url)) { |
301 return fHandlers[i]->handle(request, connection, upload_data, up load_data_size); | 349 return fHandlers[i]->handle(request, connection, url, method, up load_data, |
350 upload_data_size); | |
302 } | 351 } |
303 } | 352 } |
304 return MHD_NO; | 353 return MHD_NO; |
305 } | 354 } |
306 | 355 |
307 private: | 356 private: |
308 SkTArray<UrlHandler*> fHandlers; | 357 SkTArray<UrlHandler*> fHandlers; |
309 }; | 358 }; |
310 | 359 |
311 const UrlManager kUrlManager; | 360 const UrlManager kUrlManager; |
(...skipping 28 matching lines...) Expand all Loading... | |
340 MHD_stop_daemon(daemon); | 389 MHD_stop_daemon(daemon); |
341 return 0; | 390 return 0; |
342 } | 391 } |
343 | 392 |
344 #if !defined SK_BUILD_FOR_IOS | 393 #if !defined SK_BUILD_FOR_IOS |
345 int main(int argc, char** argv) { | 394 int main(int argc, char** argv) { |
346 SkCommandLineFlags::Parse(argc, argv); | 395 SkCommandLineFlags::Parse(argc, argv); |
347 return skiaserve_main(); | 396 return skiaserve_main(); |
348 } | 397 } |
349 #endif | 398 #endif |
OLD | NEW |