From cdad12f3b14e7cb4c1aa03990ea8044a3f204403 Mon Sep 17 00:00:00 2001 From: joshualitt Date: Mon, 8 Feb 2016 07:08:21 -0800 Subject: [PATCH] Create image cache for use by json canvas BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1670153005 Review URL: https://codereview.chromium.org/1670153005 --- gyp/skiaserve.gyp | 1 + gyp/tools.gyp | 21 ++++++++++++ tools/UrlDataManager.cpp | 44 +++++++++++++++++++++++++ tools/UrlDataManager.h | 76 +++++++++++++++++++++++++++++++++++++++++++ tools/skiaserve/skiaserve.cpp | 36 ++++++++++++++++++-- 5 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 tools/UrlDataManager.cpp create mode 100644 tools/UrlDataManager.h diff --git a/gyp/skiaserve.gyp b/gyp/skiaserve.gyp index c133762..58fdea1 100644 --- a/gyp/skiaserve.gyp +++ b/gyp/skiaserve.gyp @@ -40,6 +40,7 @@ 'tools.gyp:crash_handler', 'tools.gyp:proc_stats', 'tools.gyp:resources', + 'tools.gyp:url_data_manager', ], }, ], diff --git a/gyp/tools.gyp b/gyp/tools.gyp index b585e16..e303669 100644 --- a/gyp/tools.gyp +++ b/gyp/tools.gyp @@ -404,6 +404,27 @@ }, }, { + 'target_name': 'url_data_manager', + 'type': 'static_library', + 'sources': [ + '../tools/UrlDataManager.h', + '../tools/UrlDataManager.cpp', + ], + 'dependencies': [ + 'skia_lib.gyp:skia_lib', + ], + 'include_dirs': [ + '../include/private', + '../src/core', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../include/private', + '../tools', + ], + }, + }, + { 'target_name': 'whitelist_typefaces', 'type': 'executable', 'sources': [ diff --git a/tools/UrlDataManager.cpp b/tools/UrlDataManager.cpp new file mode 100644 index 0000000..a30d8ba --- /dev/null +++ b/tools/UrlDataManager.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "UrlDataManager.h" + +bool operator==(const SkData& a, const SkData& b) { + return a.equals(&b); +} + +UrlDataManager::UrlDataManager(SkString rootUrl) : fRootUrl(rootUrl), fDataId(0) {} + +SkString UrlDataManager::addData(SkData* data, const char* contentType) { + UrlData* urlData = fCache.find(*data); + if (fCache.find(*data)) { + SkASSERT(data->equals(urlData->fData.get())); + return urlData->fUrl; + } + + urlData = new UrlData; + urlData->fData.reset(SkRef(data)); + urlData->fContentType.set(contentType); + urlData->fUrl.appendf("%s/%d", fRootUrl.c_str(), fDataId++); + + fCache.add(urlData); + + SkASSERT(!fUrlLookup.find(urlData->fUrl)); + fUrlLookup.add(urlData); + return urlData->fUrl; +} + +void UrlDataManager::reset() { + SkTDynamicHash::Iter iter(&fCache); + while (!iter.done()) { + UrlData* urlData = &(*iter); + urlData->unref(); + ++iter; + } + + fCache.rewind(); +} diff --git a/tools/UrlDataManager.h b/tools/UrlDataManager.h new file mode 100644 index 0000000..b047eda --- /dev/null +++ b/tools/UrlDataManager.h @@ -0,0 +1,76 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkUrlDataManager_DEFINED +#define SkUrlDataManager_DEFINED + +#include "SkChecksum.h" +#include "SkData.h" +#include "SkString.h" +#include "SkTDynamicHash.h" + +/* + * A simple class which allows clients to add opaque data types, and returns a url where this data + * will be hosted. Its up to the owner of this class to actually serve the data. + */ +bool operator==(const SkData& a, const SkData& b); + +class UrlDataManager { +public: + UrlDataManager(SkString rootUrl); + ~UrlDataManager() { this->reset(); } + + /* + * Adds a data blob to the cache with a particular content type. UrlDataManager will hash + * the blob data to ensure uniqueness + */ + SkString addData(SkData*, const char* contentType); + + struct UrlData : public SkRefCnt { + SkString fUrl; + SkString fContentType; + SkAutoTUnref fData; + }; + + /* + * returns the UrlData object which should be hosted at 'url' + */ + UrlData* getDataFromUrl(SkString url) { + return fUrlLookup.find(url); + } + void reset(); + +private: + struct LookupTrait { + // We use the data as a hash, this is not really optimal but is fine until proven otherwise + static const SkData& GetKey(const UrlData& data) { + return *data.fData.get(); + } + + static uint32_t Hash(const SkData& key) { + return SkChecksum::Murmur3(key.bytes(), key.size()); + } + }; + + struct ReverseLookupTrait { + static const SkString& GetKey(const UrlData& data) { + return data.fUrl; + } + + static uint32_t Hash(const SkString& key) { + return SkChecksum::Murmur3(key.c_str(), strlen(key.c_str())); + } + }; + + + SkString fRootUrl; + SkTDynamicHash fCache; + SkTDynamicHash fUrlLookup; + uint32_t fDataId; +}; + +#endif diff --git a/tools/skiaserve/skiaserve.cpp b/tools/skiaserve/skiaserve.cpp index 85e9c87..a8ddcdf 100644 --- a/tools/skiaserve/skiaserve.cpp +++ b/tools/skiaserve/skiaserve.cpp @@ -18,6 +18,8 @@ #include "SkStream.h" #include "SkSurface.h" +#include "UrlDataManager.h" + #include #include @@ -63,10 +65,11 @@ struct UploadContext { }; struct Request { - Request() : fUploadContext(nullptr) {} + Request(SkString rootUrl) : fUploadContext(nullptr), fUrlDataManager(rootUrl) {} UploadContext* fUploadContext; SkAutoTUnref fPicture; SkAutoTUnref fDebugCanvas; + UrlDataManager fUrlDataManager; }; // TODO factor this out into functions, also handle CPU path @@ -99,6 +102,7 @@ SkData* writeCanvasToPng(SkCanvas* canvas) { } // write to png + // TODO encoding to png can be quite slow, we should investigate bmp SkData* png = SkImageEncoder::EncodeData(bmp, SkImageEncoder::kPNG_Type, 100); if (!png) { fprintf(stderr, "Can't encode to png\n"); @@ -411,6 +415,33 @@ public: } }; +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 commands; + SkStrSplit(url, "/", &commands); + + if (!request->fPicture.get() || commands.count() != 2) { + return MHD_NO; + } + + SkAutoTUnref 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: @@ -436,6 +467,7 @@ public: fHandlers.push_back(new CmdHandler); fHandlers.push_back(new InfoHandler); fHandlers.push_back(new DownloadHandler); + fHandlers.push_back(new DataHandler); } ~UrlManager() { @@ -476,7 +508,7 @@ int answer_to_connection(void* cls, struct MHD_Connection* connection, } int skiaserve_main() { - Request request; // This simple server has one request + Request request(SkString("/data")); // This simple server has one request struct MHD_Daemon* daemon; // TODO Add option to bind this strictly to an address, e.g. localhost, for security. daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, FLAGS_port, nullptr, nullptr, -- 2.7.4