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: tools/skiaserve/skiaserve.cpp

Issue 1651403003: Modify skiaserve to support drawTo and /cmd/N (Closed) Base URL: https://skia.googlesource.com/skia.git@skiaserve-9-fixcrash
Patch Set: handle /cmd 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') | no next file » | 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 #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
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
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
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
OLDNEW
« no previous file with comments | « gyp/skiaserve.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698