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

Side by Side Diff: tools/skiaserve/skiaserve.cpp

Issue 1737643003: Move urlhandlers out of skiaserve.cpp (Closed) Base URL: https://skia.googlesource.com/skia@skiaserve-4
Patch Set: rebase Created 4 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 | « gyp/skiaserve.gyp ('k') | tools/skiaserve/urlhandlers/BreakHandler.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 10
11 #include "Request.h" 11 #include "Request.h"
12 #include "Response.h" 12 #include "Response.h"
13 13
14 #include "SkCanvas.h"
15 #include "SkCommandLineFlags.h" 14 #include "SkCommandLineFlags.h"
16 #include "SkJSONCanvas.h"
17 #include "SkPictureRecorder.h"
18 #include "SkPixelSerializer.h"
19 15
16 #include "microhttpd.h"
17
18 #include "urlhandlers/UrlHandler.h"
20 #include <sys/socket.h> 19 #include <sys/socket.h>
21 #include <microhttpd.h>
22 20
23 using namespace Response; 21 using namespace Response;
24 22
25 // To get image decoders linked in we have to do the below magic 23 // To get image decoders linked in we have to do the below magic
26 #include "SkForceLinking.h" 24 #include "SkForceLinking.h"
27 #include "SkImageDecoder.h" 25 #include "SkImageDecoder.h"
28 __SK_FORCE_IMAGE_DECODER_LINKING; 26 __SK_FORCE_IMAGE_DECODER_LINKING;
29 27
30 DEFINE_int32(port, 8888, "The port to listen on."); 28 DEFINE_int32(port, 8888, "The port to listen on.");
31 29
32 static const size_t kBufferSize = 1024;
33
34 static int process_upload_data(void* cls, enum MHD_ValueKind kind,
35 const char* key, const char* filename,
36 const char* content_type, const char* transfer_en coding,
37 const char* data, uint64_t off, size_t size) {
38 struct UploadContext* uc = reinterpret_cast<UploadContext*>(cls);
39
40 if (0 != size) {
41 uc->fStream.write(data, size);
42 }
43 return MHD_YES;
44 }
45
46 class UrlHandler {
47 public:
48 virtual ~UrlHandler() {}
49 virtual bool canHandle(const char* method, const char* url) = 0;
50 virtual int handle(Request* request, MHD_Connection* connection,
51 const char* url, const char* method,
52 const char* upload_data, size_t* upload_data_size) = 0;
53 };
54
55 class CmdHandler : public UrlHandler {
56 public:
57 bool canHandle(const char* method, const char* url) override {
58 const char* kBasePath = "/cmd";
59 return 0 == strncmp(url, kBasePath, strlen(kBasePath));
60 }
61
62 int handle(Request* request, MHD_Connection* connection,
63 const char* url, const char* method,
64 const char* upload_data, size_t* upload_data_size) override {
65 SkTArray<SkString> commands;
66 SkStrSplit(url, "/", &commands);
67
68 if (!request->fPicture.get() || commands.count() > 3) {
69 return MHD_NO;
70 }
71
72 // /cmd or /cmd/N
73 if (0 == strcmp(method, MHD_HTTP_METHOD_GET)) {
74 int n;
75 if (commands.count() == 1) {
76 n = request->fDebugCanvas->getSize() - 1;
77 } else {
78 sscanf(commands[1].c_str(), "%d", &n);
79 }
80 return SendJSON(connection, request, n);
81 }
82
83 // /cmd/N, for now only delete supported
84 if (commands.count() == 2 && 0 == strcmp(method, MHD_HTTP_METHOD_DELETE) ) {
85 int n;
86 sscanf(commands[1].c_str(), "%d", &n);
87 request->fDebugCanvas->deleteDrawCommandAt(n);
88 return SendOK(connection);
89 }
90
91 // /cmd/N/[0|1]
92 if (commands.count() == 3 && 0 == strcmp(method, MHD_HTTP_METHOD_POST)) {
93 int n, toggle;
94 sscanf(commands[1].c_str(), "%d", &n);
95 sscanf(commands[2].c_str(), "%d", &toggle);
96 request->fDebugCanvas->toggleCommand(n, toggle);
97 return SendOK(connection);
98 }
99
100 return MHD_NO;
101 }
102 };
103
104 class ImgHandler : public UrlHandler {
105 public:
106 bool canHandle(const char* method, const char* url) override {
107 static const char* kBasePath = "/img";
108 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
109 0 == strncmp(url, kBasePath, strlen(kBasePath));
110 }
111
112 int handle(Request* request, MHD_Connection* connection,
113 const char* url, const char* method,
114 const char* upload_data, size_t* upload_data_size) override {
115 SkTArray<SkString> commands;
116 SkStrSplit(url, "/", &commands);
117
118 if (!request->fPicture.get() || commands.count() > 2) {
119 return MHD_NO;
120 }
121
122 int n;
123 // /img or /img/N
124 if (commands.count() == 1) {
125 n = request->fDebugCanvas->getSize() - 1;
126 } else {
127 sscanf(commands[1].c_str(), "%d", &n);
128 }
129
130 SkAutoTUnref<SkData> data(request->drawToPng(n));
131 return SendData(connection, data, "image/png");
132 }
133 };
134
135 class BreakHandler : public UrlHandler {
136 public:
137 bool canHandle(const char* method, const char* url) override {
138 static const char* kBasePath = "/break";
139 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
140 0 == strncmp(url, kBasePath, strlen(kBasePath));
141 }
142
143 static SkColor GetPixel(Request* request, int x, int y) {
144 SkCanvas* canvas = request->getCanvas();
145 canvas->flush();
146 SkAutoTDelete<SkBitmap> bitmap(request->getBitmapFromCanvas(canvas));
147 SkASSERT(bitmap);
148 bitmap->lockPixels();
149 uint8_t* start = ((uint8_t*) bitmap->getPixels()) + (y * Request::kImage Width + x) * 4;
150 SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
151 bitmap->unlockPixels();
152 return result;
153 }
154
155 int handle(Request* request, MHD_Connection* connection,
156 const char* url, const char* method,
157 const char* upload_data, size_t* upload_data_size) override {
158 SkTArray<SkString> commands;
159 SkStrSplit(url, "/", &commands);
160
161 if (!request->fPicture.get() || commands.count() != 4) {
162 return MHD_NO;
163 }
164
165 // /break/<n>/<x>/<y>
166 int n;
167 sscanf(commands[1].c_str(), "%d", &n);
168 int x;
169 sscanf(commands[2].c_str(), "%d", &x);
170 int y;
171 sscanf(commands[3].c_str(), "%d", &y);
172
173 int count = request->fDebugCanvas->getSize();
174 SkASSERT(n < count);
175
176 SkCanvas* canvas = request->getCanvas();
177 canvas->clear(SK_ColorWHITE);
178 int saveCount = canvas->save();
179 for (int i = 0; i <= n; ++i) {
180 request->fDebugCanvas->getDrawCommandAt(i)->execute(canvas);
181 }
182 SkColor target = GetPixel(request, x, y);
183 Json::Value response(Json::objectValue);
184 Json::Value startColor(Json::arrayValue);
185 startColor.append(Json::Value(SkColorGetR(target)));
186 startColor.append(Json::Value(SkColorGetG(target)));
187 startColor.append(Json::Value(SkColorGetB(target)));
188 startColor.append(Json::Value(SkColorGetA(target)));
189 response["startColor"] = startColor;
190 response["endColor"] = startColor;
191 response["endOp"] = Json::Value(n);
192 for (int i = n + 1; i < n + count; ++i) {
193 int index = i % count;
194 if (index == 0) {
195 // reset canvas for wraparound
196 canvas->restoreToCount(saveCount);
197 canvas->clear(SK_ColorWHITE);
198 saveCount = canvas->save();
199 }
200 request->fDebugCanvas->getDrawCommandAt(index)->execute(canvas);
201 SkColor current = GetPixel(request, x, y);
202 if (current != target) {
203 Json::Value endColor(Json::arrayValue);
204 endColor.append(Json::Value(SkColorGetR(current)));
205 endColor.append(Json::Value(SkColorGetG(current)));
206 endColor.append(Json::Value(SkColorGetB(current)));
207 endColor.append(Json::Value(SkColorGetA(current)));
208 response["endColor"] = endColor;
209 response["endOp"] = Json::Value(index);
210 break;
211 }
212 }
213 canvas->restoreToCount(saveCount);
214 SkDynamicMemoryWStream stream;
215 stream.writeText(Json::FastWriter().write(response).c_str());
216 SkAutoTUnref<SkData> data(stream.copyToData());
217 return SendData(connection, data, "application/json");
218 }
219 };
220
221 /**
222 Updates the clip visualization alpha. On all subsequent /img requests, the cl ip will be drawn in
223 black with the specified alpha. 0 = no visible clip, 255 = fully opaque clip.
224 */
225 class ClipAlphaHandler : public UrlHandler {
226 public:
227 bool canHandle(const char* method, const char* url) override {
228 static const char* kBasePath = "/clipAlpha/";
229 return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
230 0 == strncmp(url, kBasePath, strlen(kBasePath));
231 }
232
233 int handle(Request* request, MHD_Connection* connection,
234 const char* url, const char* method,
235 const char* upload_data, size_t* upload_data_size) override {
236 SkTArray<SkString> commands;
237 SkStrSplit(url, "/", &commands);
238
239 if (!request->fPicture.get() || commands.count() != 2) {
240 return MHD_NO;
241 }
242
243 int alpha;
244 sscanf(commands[1].c_str(), "%d", &alpha);
245
246 request->fDebugCanvas->setClipVizColor(SkColorSetARGB(alpha, 0, 0, 0));
247 return SendOK(connection);
248 }
249 };
250
251 /**
252 Controls whether GPU rendering is enabled. Posting to /enableGPU/1 turns GPU on, /enableGPU/0
253 disables it.
254 */
255 class EnableGPUHandler : public UrlHandler {
256 public:
257 bool canHandle(const char* method, const char* url) override {
258 static const char* kBasePath = "/enableGPU/";
259 return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
260 0 == strncmp(url, kBasePath, strlen(kBasePath));
261 }
262
263 int handle(Request* request, MHD_Connection* connection,
264 const char* url, const char* method,
265 const char* upload_data, size_t* upload_data_size) override {
266 SkTArray<SkString> commands;
267 SkStrSplit(url, "/", &commands);
268
269 if (commands.count() != 2) {
270 return MHD_NO;
271 }
272
273 int enable;
274 sscanf(commands[1].c_str(), "%d", &enable);
275
276 if (enable) {
277 SkSurface* surface = request->createGPUSurface();
278 if (surface) {
279 request->fSurface.reset(surface);
280 request->fGPUEnabled = true;
281 return SendOK(connection);
282 }
283 return SendError(connection, "Unable to create GPU surface");
284 }
285 request->fSurface.reset(request->createCPUSurface());
286 request->fGPUEnabled = false;
287 return SendOK(connection);
288 }
289 };
290
291 class PostHandler : public UrlHandler {
292 public:
293 bool canHandle(const char* method, const char* url) override {
294 return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
295 0 == strcmp(url, "/new");
296 }
297
298 int handle(Request* request, MHD_Connection* connection,
299 const char* url, const char* method,
300 const char* upload_data, size_t* upload_data_size) override {
301 UploadContext* uc = request->fUploadContext;
302
303 // New connection
304 if (!uc) {
305 // TODO make this a method on request
306 uc = new UploadContext;
307 uc->connection = connection;
308 uc->fPostProcessor = MHD_create_post_processor(connection, kBufferSi ze,
309 &process_upload_data, uc);
310 SkASSERT(uc->fPostProcessor);
311
312 request->fUploadContext = uc;
313 return MHD_YES;
314 }
315
316 // in process upload
317 if (0 != *upload_data_size) {
318 SkASSERT(uc->fPostProcessor);
319 MHD_post_process(uc->fPostProcessor, upload_data, *upload_data_size) ;
320 *upload_data_size = 0;
321 return MHD_YES;
322 }
323
324 // end of upload
325 MHD_destroy_post_processor(uc->fPostProcessor);
326 uc->fPostProcessor = nullptr;
327
328 // parse picture from stream
329 request->fPicture.reset(
330 SkPicture::CreateFromStream(request->fUploadContext->fStream.detachA sStream()));
331 if (!request->fPicture.get()) {
332 fprintf(stderr, "Could not create picture from stream.\n");
333 return MHD_NO;
334 }
335
336 // pour picture into debug canvas
337 request->fDebugCanvas.reset(new SkDebugCanvas(Request::kImageWidth,
338 Request::kImageHeight));
339 request->fDebugCanvas->drawPicture(request->fPicture);
340
341 // clear upload context
342 delete request->fUploadContext;
343 request->fUploadContext = nullptr;
344
345 return SendTemplate(connection, true, "/");
346 }
347 };
348
349 class DownloadHandler : public UrlHandler {
350 public:
351 bool canHandle(const char* method, const char* url) override {
352 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
353 0 == strcmp(url, "/download");
354 }
355
356 int handle(Request* request, MHD_Connection* connection,
357 const char* url, const char* method,
358 const char* upload_data, size_t* upload_data_size) override {
359 if (!request->fPicture.get()) {
360 return MHD_NO;
361 }
362
363 // TODO move to a function
364 // Playback into picture recorder
365 SkPictureRecorder recorder;
366 SkCanvas* canvas = recorder.beginRecording(Request::kImageWidth,
367 Request::kImageHeight);
368
369 request->fDebugCanvas->draw(canvas);
370
371 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
372
373 SkDynamicMemoryWStream outStream;
374
375 SkAutoTUnref<SkPixelSerializer> serializer(SkImageEncoder::CreatePixelSe rializer());
376 picture->serialize(&outStream, serializer);
377
378 SkAutoTUnref<SkData> data(outStream.copyToData());
379
380 // TODO fancier name handling
381 return SendData(connection, data, "application/octet-stream", true,
382 "attachment; filename=something.skp;");
383 }
384 };
385
386 class InfoHandler : public UrlHandler {
387 public:
388 bool canHandle(const char* method, const char* url) override {
389 const char* kBaseName = "/info";
390 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
391 0 == strncmp(url, kBaseName, strlen(kBaseName));
392 }
393
394 int handle(Request* request, MHD_Connection* connection,
395 const char* url, const char* method,
396 const char* upload_data, size_t* upload_data_size) override {
397 SkTArray<SkString> commands;
398 SkStrSplit(url, "/", &commands);
399
400 if (!request->fPicture.get() || commands.count() > 2) {
401 return MHD_NO;
402 }
403
404 // drawTo
405 SkAutoTUnref<SkSurface> surface(request->createCPUSurface());
406 SkCanvas* canvas = surface->getCanvas();
407
408 int n;
409 // /info or /info/N
410 if (commands.count() == 1) {
411 n = request->fDebugCanvas->getSize() - 1;
412 } else {
413 sscanf(commands[1].c_str(), "%d", &n);
414 }
415
416 // TODO this is really slow and we should cache the matrix and clip
417 request->fDebugCanvas->drawTo(canvas, n);
418
419 // make some json
420 SkMatrix vm = request->fDebugCanvas->getCurrentMatrix();
421 SkIRect clip = request->fDebugCanvas->getCurrentClip();
422 Json::Value info(Json::objectValue);
423 info["ViewMatrix"] = SkJSONCanvas::MakeMatrix(vm);
424 info["ClipRect"] = SkJSONCanvas::MakeIRect(clip);
425
426 std::string json = Json::FastWriter().write(info);
427
428 // We don't want the null terminator so strlen is correct
429 SkAutoTUnref<SkData> data(SkData::NewWithCopy(json.c_str(), strlen(json. c_str())));
430 return SendData(connection, data, "application/json");
431 }
432 };
433
434 class DataHandler : public UrlHandler {
435 public:
436 bool canHandle(const char* method, const char* url) override {
437 static const char* kBaseUrl = "/data";
438 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
439 0 == strncmp(url, kBaseUrl, strlen(kBaseUrl));
440 }
441
442 int handle(Request* request, MHD_Connection* connection,
443 const char* url, const char* method,
444 const char* upload_data, size_t* upload_data_size) override {
445 SkTArray<SkString> commands;
446 SkStrSplit(url, "/", &commands);
447
448 if (!request->fPicture.get() || commands.count() != 2) {
449 return MHD_NO;
450 }
451
452 SkAutoTUnref<UrlDataManager::UrlData> urlData(
453 SkRef(request->fUrlDataManager.getDataFromUrl(SkString(url))));
454
455 if (urlData) {
456 return SendData(connection, urlData->fData.get(), urlData->fContentT ype.c_str());
457 }
458 return MHD_NO;
459 }
460 };
461
462 class RootHandler : public UrlHandler {
463 public:
464 bool canHandle(const char* method, const char* url) override {
465 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
466 0 == strcmp(url, "/");
467 }
468
469 int handle(Request* request, MHD_Connection* connection,
470 const char* url, const char* method,
471 const char* upload_data, size_t* upload_data_size) override {
472 return SendTemplate(connection);
473 }
474 };
475
476 class UrlManager { 30 class UrlManager {
477 public: 31 public:
478 UrlManager() { 32 UrlManager() {
479 // Register handlers 33 // Register handlers
480 fHandlers.push_back(new RootHandler); 34 fHandlers.push_back(new RootHandler);
481 fHandlers.push_back(new PostHandler); 35 fHandlers.push_back(new PostHandler);
482 fHandlers.push_back(new ImgHandler); 36 fHandlers.push_back(new ImgHandler);
483 fHandlers.push_back(new ClipAlphaHandler); 37 fHandlers.push_back(new ClipAlphaHandler);
484 fHandlers.push_back(new EnableGPUHandler); 38 fHandlers.push_back(new EnableGPUHandler);
485 fHandlers.push_back(new CmdHandler); 39 fHandlers.push_back(new CmdHandler);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 MHD_stop_daemon(daemon); 101 MHD_stop_daemon(daemon);
548 return 0; 102 return 0;
549 } 103 }
550 104
551 #if !defined SK_BUILD_FOR_IOS 105 #if !defined SK_BUILD_FOR_IOS
552 int main(int argc, char** argv) { 106 int main(int argc, char** argv) {
553 SkCommandLineFlags::Parse(argc, argv); 107 SkCommandLineFlags::Parse(argc, argv);
554 return skiaserve_main(); 108 return skiaserve_main();
555 } 109 }
556 #endif 110 #endif
OLDNEW
« no previous file with comments | « gyp/skiaserve.gyp ('k') | tools/skiaserve/urlhandlers/BreakHandler.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698