| Index: tools/skiaserve/skiaserve.cpp
|
| diff --git a/tools/skiaserve/skiaserve.cpp b/tools/skiaserve/skiaserve.cpp
|
| index d5a0132d0d189833ed8d48c927c1ba4f56330471..622fbf114ba8d567844c549c606e034de555d384 100644
|
| --- a/tools/skiaserve/skiaserve.cpp
|
| +++ b/tools/skiaserve/skiaserve.cpp
|
| @@ -11,14 +11,12 @@
|
| #include "Request.h"
|
| #include "Response.h"
|
|
|
| -#include "SkCanvas.h"
|
| #include "SkCommandLineFlags.h"
|
| -#include "SkJSONCanvas.h"
|
| -#include "SkPictureRecorder.h"
|
| -#include "SkPixelSerializer.h"
|
|
|
| +#include "microhttpd.h"
|
| +
|
| +#include "urlhandlers/UrlHandler.h"
|
| #include <sys/socket.h>
|
| -#include <microhttpd.h>
|
|
|
| using namespace Response;
|
|
|
| @@ -29,450 +27,6 @@ __SK_FORCE_IMAGE_DECODER_LINKING;
|
|
|
| DEFINE_int32(port, 8888, "The port to listen on.");
|
|
|
| -static const size_t kBufferSize = 1024;
|
| -
|
| -static int process_upload_data(void* cls, enum MHD_ValueKind kind,
|
| - const char* key, const char* filename,
|
| - const char* content_type, const char* transfer_encoding,
|
| - const char* data, uint64_t off, size_t size) {
|
| - struct UploadContext* uc = reinterpret_cast<UploadContext*>(cls);
|
| -
|
| - if (0 != size) {
|
| - uc->fStream.write(data, size);
|
| - }
|
| - return MHD_YES;
|
| -}
|
| -
|
| -class UrlHandler {
|
| -public:
|
| - virtual ~UrlHandler() {}
|
| - virtual bool canHandle(const char* method, const char* url) = 0;
|
| - virtual int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) = 0;
|
| -};
|
| -
|
| -class CmdHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - const char* kBasePath = "/cmd";
|
| - return 0 == strncmp(url, kBasePath, strlen(kBasePath));
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - SkTArray<SkString> commands;
|
| - SkStrSplit(url, "/", &commands);
|
| -
|
| - if (!request->fPicture.get() || commands.count() > 3) {
|
| - return MHD_NO;
|
| - }
|
| -
|
| - // /cmd or /cmd/N
|
| - if (0 == strcmp(method, MHD_HTTP_METHOD_GET)) {
|
| - int n;
|
| - if (commands.count() == 1) {
|
| - n = request->fDebugCanvas->getSize() - 1;
|
| - } else {
|
| - sscanf(commands[1].c_str(), "%d", &n);
|
| - }
|
| - return SendJSON(connection, request, n);
|
| - }
|
| -
|
| - // /cmd/N, for now only delete supported
|
| - if (commands.count() == 2 && 0 == strcmp(method, MHD_HTTP_METHOD_DELETE)) {
|
| - int n;
|
| - sscanf(commands[1].c_str(), "%d", &n);
|
| - request->fDebugCanvas->deleteDrawCommandAt(n);
|
| - return SendOK(connection);
|
| - }
|
| -
|
| - // /cmd/N/[0|1]
|
| - if (commands.count() == 3 && 0 == strcmp(method, MHD_HTTP_METHOD_POST)) {
|
| - int n, toggle;
|
| - sscanf(commands[1].c_str(), "%d", &n);
|
| - sscanf(commands[2].c_str(), "%d", &toggle);
|
| - request->fDebugCanvas->toggleCommand(n, toggle);
|
| - return SendOK(connection);
|
| - }
|
| -
|
| - return MHD_NO;
|
| - }
|
| -};
|
| -
|
| -class ImgHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - static const char* kBasePath = "/img";
|
| - return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
|
| - 0 == strncmp(url, kBasePath, strlen(kBasePath));
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - SkTArray<SkString> commands;
|
| - SkStrSplit(url, "/", &commands);
|
| -
|
| - if (!request->fPicture.get() || commands.count() > 2) {
|
| - return MHD_NO;
|
| - }
|
| -
|
| - int n;
|
| - // /img or /img/N
|
| - if (commands.count() == 1) {
|
| - n = request->fDebugCanvas->getSize() - 1;
|
| - } else {
|
| - sscanf(commands[1].c_str(), "%d", &n);
|
| - }
|
| -
|
| - SkAutoTUnref<SkData> data(request->drawToPng(n));
|
| - return SendData(connection, data, "image/png");
|
| - }
|
| -};
|
| -
|
| -class BreakHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - static const char* kBasePath = "/break";
|
| - return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
|
| - 0 == strncmp(url, kBasePath, strlen(kBasePath));
|
| - }
|
| -
|
| - static SkColor GetPixel(Request* request, int x, int y) {
|
| - SkCanvas* canvas = request->getCanvas();
|
| - canvas->flush();
|
| - SkAutoTDelete<SkBitmap> bitmap(request->getBitmapFromCanvas(canvas));
|
| - SkASSERT(bitmap);
|
| - bitmap->lockPixels();
|
| - uint8_t* start = ((uint8_t*) bitmap->getPixels()) + (y * Request::kImageWidth + x) * 4;
|
| - SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
|
| - bitmap->unlockPixels();
|
| - return result;
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - SkTArray<SkString> commands;
|
| - SkStrSplit(url, "/", &commands);
|
| -
|
| - if (!request->fPicture.get() || commands.count() != 4) {
|
| - return MHD_NO;
|
| - }
|
| -
|
| - // /break/<n>/<x>/<y>
|
| - int n;
|
| - sscanf(commands[1].c_str(), "%d", &n);
|
| - int x;
|
| - sscanf(commands[2].c_str(), "%d", &x);
|
| - int y;
|
| - sscanf(commands[3].c_str(), "%d", &y);
|
| -
|
| - int count = request->fDebugCanvas->getSize();
|
| - SkASSERT(n < count);
|
| -
|
| - SkCanvas* canvas = request->getCanvas();
|
| - canvas->clear(SK_ColorWHITE);
|
| - int saveCount = canvas->save();
|
| - for (int i = 0; i <= n; ++i) {
|
| - request->fDebugCanvas->getDrawCommandAt(i)->execute(canvas);
|
| - }
|
| - SkColor target = GetPixel(request, x, y);
|
| - Json::Value response(Json::objectValue);
|
| - Json::Value startColor(Json::arrayValue);
|
| - startColor.append(Json::Value(SkColorGetR(target)));
|
| - startColor.append(Json::Value(SkColorGetG(target)));
|
| - startColor.append(Json::Value(SkColorGetB(target)));
|
| - startColor.append(Json::Value(SkColorGetA(target)));
|
| - response["startColor"] = startColor;
|
| - response["endColor"] = startColor;
|
| - response["endOp"] = Json::Value(n);
|
| - for (int i = n + 1; i < n + count; ++i) {
|
| - int index = i % count;
|
| - if (index == 0) {
|
| - // reset canvas for wraparound
|
| - canvas->restoreToCount(saveCount);
|
| - canvas->clear(SK_ColorWHITE);
|
| - saveCount = canvas->save();
|
| - }
|
| - request->fDebugCanvas->getDrawCommandAt(index)->execute(canvas);
|
| - SkColor current = GetPixel(request, x, y);
|
| - if (current != target) {
|
| - Json::Value endColor(Json::arrayValue);
|
| - endColor.append(Json::Value(SkColorGetR(current)));
|
| - endColor.append(Json::Value(SkColorGetG(current)));
|
| - endColor.append(Json::Value(SkColorGetB(current)));
|
| - endColor.append(Json::Value(SkColorGetA(current)));
|
| - response["endColor"] = endColor;
|
| - response["endOp"] = Json::Value(index);
|
| - break;
|
| - }
|
| - }
|
| - canvas->restoreToCount(saveCount);
|
| - SkDynamicMemoryWStream stream;
|
| - stream.writeText(Json::FastWriter().write(response).c_str());
|
| - SkAutoTUnref<SkData> data(stream.copyToData());
|
| - return SendData(connection, data, "application/json");
|
| - }
|
| -};
|
| -
|
| -/**
|
| - Updates the clip visualization alpha. On all subsequent /img requests, the clip will be drawn in
|
| - black with the specified alpha. 0 = no visible clip, 255 = fully opaque clip.
|
| - */
|
| -class ClipAlphaHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - static const char* kBasePath = "/clipAlpha/";
|
| - return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
|
| - 0 == strncmp(url, kBasePath, strlen(kBasePath));
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - SkTArray<SkString> commands;
|
| - SkStrSplit(url, "/", &commands);
|
| -
|
| - if (!request->fPicture.get() || commands.count() != 2) {
|
| - return MHD_NO;
|
| - }
|
| -
|
| - int alpha;
|
| - sscanf(commands[1].c_str(), "%d", &alpha);
|
| -
|
| - request->fDebugCanvas->setClipVizColor(SkColorSetARGB(alpha, 0, 0, 0));
|
| - return SendOK(connection);
|
| - }
|
| -};
|
| -
|
| -/**
|
| - Controls whether GPU rendering is enabled. Posting to /enableGPU/1 turns GPU on, /enableGPU/0
|
| - disables it.
|
| - */
|
| -class EnableGPUHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - static const char* kBasePath = "/enableGPU/";
|
| - return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
|
| - 0 == strncmp(url, kBasePath, strlen(kBasePath));
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - SkTArray<SkString> commands;
|
| - SkStrSplit(url, "/", &commands);
|
| -
|
| - if (commands.count() != 2) {
|
| - return MHD_NO;
|
| - }
|
| -
|
| - int enable;
|
| - sscanf(commands[1].c_str(), "%d", &enable);
|
| -
|
| - if (enable) {
|
| - SkSurface* surface = request->createGPUSurface();
|
| - if (surface) {
|
| - request->fSurface.reset(surface);
|
| - request->fGPUEnabled = true;
|
| - return SendOK(connection);
|
| - }
|
| - return SendError(connection, "Unable to create GPU surface");
|
| - }
|
| - request->fSurface.reset(request->createCPUSurface());
|
| - request->fGPUEnabled = false;
|
| - return SendOK(connection);
|
| - }
|
| -};
|
| -
|
| -class PostHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
|
| - 0 == strcmp(url, "/new");
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - UploadContext* uc = request->fUploadContext;
|
| -
|
| - // New connection
|
| - if (!uc) {
|
| - // TODO make this a method on request
|
| - uc = new UploadContext;
|
| - uc->connection = connection;
|
| - uc->fPostProcessor = MHD_create_post_processor(connection, kBufferSize,
|
| - &process_upload_data, uc);
|
| - SkASSERT(uc->fPostProcessor);
|
| -
|
| - request->fUploadContext = uc;
|
| - return MHD_YES;
|
| - }
|
| -
|
| - // in process upload
|
| - if (0 != *upload_data_size) {
|
| - SkASSERT(uc->fPostProcessor);
|
| - MHD_post_process(uc->fPostProcessor, upload_data, *upload_data_size);
|
| - *upload_data_size = 0;
|
| - return MHD_YES;
|
| - }
|
| -
|
| - // end of upload
|
| - MHD_destroy_post_processor(uc->fPostProcessor);
|
| - uc->fPostProcessor = nullptr;
|
| -
|
| - // parse picture from stream
|
| - request->fPicture.reset(
|
| - SkPicture::CreateFromStream(request->fUploadContext->fStream.detachAsStream()));
|
| - if (!request->fPicture.get()) {
|
| - fprintf(stderr, "Could not create picture from stream.\n");
|
| - return MHD_NO;
|
| - }
|
| -
|
| - // pour picture into debug canvas
|
| - request->fDebugCanvas.reset(new SkDebugCanvas(Request::kImageWidth,
|
| - Request::kImageHeight));
|
| - request->fDebugCanvas->drawPicture(request->fPicture);
|
| -
|
| - // clear upload context
|
| - delete request->fUploadContext;
|
| - request->fUploadContext = nullptr;
|
| -
|
| - return SendTemplate(connection, true, "/");
|
| - }
|
| -};
|
| -
|
| -class DownloadHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
|
| - 0 == strcmp(url, "/download");
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - if (!request->fPicture.get()) {
|
| - return MHD_NO;
|
| - }
|
| -
|
| - // TODO move to a function
|
| - // Playback into picture recorder
|
| - SkPictureRecorder recorder;
|
| - SkCanvas* canvas = recorder.beginRecording(Request::kImageWidth,
|
| - Request::kImageHeight);
|
| -
|
| - request->fDebugCanvas->draw(canvas);
|
| -
|
| - SkAutoTUnref<SkPicture> picture(recorder.endRecording());
|
| -
|
| - SkDynamicMemoryWStream outStream;
|
| -
|
| - SkAutoTUnref<SkPixelSerializer> serializer(SkImageEncoder::CreatePixelSerializer());
|
| - picture->serialize(&outStream, serializer);
|
| -
|
| - SkAutoTUnref<SkData> data(outStream.copyToData());
|
| -
|
| - // TODO fancier name handling
|
| - return SendData(connection, data, "application/octet-stream", true,
|
| - "attachment; filename=something.skp;");
|
| - }
|
| -};
|
| -
|
| -class InfoHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - const char* kBaseName = "/info";
|
| - return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
|
| - 0 == strncmp(url, kBaseName, strlen(kBaseName));
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - SkTArray<SkString> commands;
|
| - SkStrSplit(url, "/", &commands);
|
| -
|
| - if (!request->fPicture.get() || commands.count() > 2) {
|
| - return MHD_NO;
|
| - }
|
| -
|
| - // drawTo
|
| - SkAutoTUnref<SkSurface> surface(request->createCPUSurface());
|
| - SkCanvas* canvas = surface->getCanvas();
|
| -
|
| - int n;
|
| - // /info or /info/N
|
| - if (commands.count() == 1) {
|
| - n = request->fDebugCanvas->getSize() - 1;
|
| - } else {
|
| - sscanf(commands[1].c_str(), "%d", &n);
|
| - }
|
| -
|
| - // TODO this is really slow and we should cache the matrix and clip
|
| - request->fDebugCanvas->drawTo(canvas, n);
|
| -
|
| - // make some json
|
| - SkMatrix vm = request->fDebugCanvas->getCurrentMatrix();
|
| - SkIRect clip = request->fDebugCanvas->getCurrentClip();
|
| - Json::Value info(Json::objectValue);
|
| - info["ViewMatrix"] = SkJSONCanvas::MakeMatrix(vm);
|
| - info["ClipRect"] = SkJSONCanvas::MakeIRect(clip);
|
| -
|
| - std::string json = Json::FastWriter().write(info);
|
| -
|
| - // We don't want the null terminator so strlen is correct
|
| - SkAutoTUnref<SkData> data(SkData::NewWithCopy(json.c_str(), strlen(json.c_str())));
|
| - return SendData(connection, data, "application/json");
|
| - }
|
| -};
|
| -
|
| -class DataHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - static const char* kBaseUrl = "/data";
|
| - return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
|
| - 0 == strncmp(url, kBaseUrl, strlen(kBaseUrl));
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - SkTArray<SkString> commands;
|
| - SkStrSplit(url, "/", &commands);
|
| -
|
| - if (!request->fPicture.get() || commands.count() != 2) {
|
| - return MHD_NO;
|
| - }
|
| -
|
| - SkAutoTUnref<UrlDataManager::UrlData> urlData(
|
| - SkRef(request->fUrlDataManager.getDataFromUrl(SkString(url))));
|
| -
|
| - if (urlData) {
|
| - return SendData(connection, urlData->fData.get(), urlData->fContentType.c_str());
|
| - }
|
| - return MHD_NO;
|
| - }
|
| -};
|
| -
|
| -class RootHandler : public UrlHandler {
|
| -public:
|
| - bool canHandle(const char* method, const char* url) override {
|
| - return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
|
| - 0 == strcmp(url, "/");
|
| - }
|
| -
|
| - int handle(Request* request, MHD_Connection* connection,
|
| - const char* url, const char* method,
|
| - const char* upload_data, size_t* upload_data_size) override {
|
| - return SendTemplate(connection);
|
| - }
|
| -};
|
| -
|
| class UrlManager {
|
| public:
|
| UrlManager() {
|
|
|