aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/skiaserve.gyp1
-rw-r--r--gyp/tools.gyp21
-rw-r--r--tools/UrlDataManager.cpp44
-rw-r--r--tools/UrlDataManager.h76
-rw-r--r--tools/skiaserve/skiaserve.cpp36
5 files changed, 176 insertions, 2 deletions
diff --git a/gyp/skiaserve.gyp b/gyp/skiaserve.gyp
index c133762b70..58fdea1fde 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 b585e16541..e303669310 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 0000000000..a30d8ba23e
--- /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<UrlData, SkData, LookupTrait>::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 0000000000..b047edacbc
--- /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<SkData> 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<UrlData, SkData, LookupTrait> fCache;
+ SkTDynamicHash<UrlData, SkString, ReverseLookupTrait> fUrlLookup;
+ uint32_t fDataId;
+};
+
+#endif
diff --git a/tools/skiaserve/skiaserve.cpp b/tools/skiaserve/skiaserve.cpp
index 85e9c87c17..a8ddcdf488 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 <sys/socket.h>
#include <microhttpd.h>
@@ -63,10 +65,11 @@ struct UploadContext {
};
struct Request {
- Request() : fUploadContext(nullptr) {}
+ Request(SkString rootUrl) : fUploadContext(nullptr), fUrlDataManager(rootUrl) {}
UploadContext* fUploadContext;
SkAutoTUnref<SkPicture> fPicture;
SkAutoTUnref<SkDebugCanvas> 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<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:
@@ -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,