summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2018-02-20 15:06:26 +0100
committerKonstantin Käfer <mail@kkaefer.com>2018-02-21 14:50:13 +0100
commit021e1ae596440cfdee5ffe75907b76069ae44307 (patch)
treeebf15ff8a72e5f14291ba37b6f297ca9a738eea4 /platform
parent06213d9145d3b20b63e235cc25678fd76dc296d0 (diff)
downloadqtlocation-mapboxgl-upstream/blob.tar.gz
[core] introduce Blob for compressed and uncompressed dataupstream/blob
- Blob is a wrapper type for a shared_ptr<const string> that has accessor functions for getting compressed and uncompressed data - Moved util::writeFile, util::readFile, util::compress, util::uncompress, decodeImage, and encodePNG to the Blob interface - Added Blob support to Request and file sources - Added Blob support to VectorTile objects - Added support for gzip decoding to util::uncompress - We're no longer compressing WebP, PNG, and JPEG data when storing in the OfflineDatabase - Android's HTTPRequest returns compressed Blobs by default One caveat is that our previous decompress function didn't support gzip, so once users upgrade to this version, their offline cache may contain both zlib-compressed data and gzip-compressed data, but older versions won't be able to decompress gzip data. On the other hand, we don't support downgrading SDKs anyway, so this shouldn't be a problem. To be on the safe side, we could bump the user_version of the SQLite DB.
Diffstat (limited to 'platform')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/UnknownContentEncodingException.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java19
-rw-r--r--platform/android/src/asset_manager_file_source.cpp5
-rw-r--r--platform/android/src/http_file_source.cpp14
-rw-r--r--platform/android/src/image.cpp12
-rwxr-xr-xplatform/android/src/native_map_view.cpp4
-rw-r--r--platform/darwin/src/http_file_source.mm5
-rw-r--r--platform/darwin/src/image.mm5
-rw-r--r--platform/darwin/test/MGLOfflineStorageTests.mm4
-rw-r--r--platform/default/asset_file_source.cpp8
-rw-r--r--platform/default/default_file_source.cpp15
-rw-r--r--platform/default/http_file_source.cpp4
-rw-r--r--platform/default/image.cpp7
-rw-r--r--platform/default/local_file_source.cpp8
-rw-r--r--platform/default/mbgl/storage/offline_database.cpp73
-rw-r--r--platform/default/mbgl/storage/offline_database.hpp2
-rw-r--r--platform/default/mbgl/storage/offline_download.cpp18
-rw-r--r--platform/default/online_file_source.cpp10
-rw-r--r--platform/default/png_writer.cpp4
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj4
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj2
-rw-r--r--platform/node/src/node_map.cpp4
-rw-r--r--platform/node/src/node_request.cpp6
-rw-r--r--platform/qt/src/http_request.cpp4
-rw-r--r--platform/qt/src/qmapboxgl.cpp4
-rw-r--r--platform/qt/src/qt_image.cpp11
-rw-r--r--platform/qt/test/qmapboxgl.test.cpp2
27 files changed, 181 insertions, 85 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/UnknownContentEncodingException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/UnknownContentEncodingException.java
new file mode 100644
index 0000000000..4debc33ee4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/UnknownContentEncodingException.java
@@ -0,0 +1,12 @@
+package com.mapbox.mapboxsdk.exceptions;
+
+/**
+ * An UnknownContentEncodingException is thrown by HTTPRequest
+ * when there aren't enough LatLng to create a bounds.
+ */
+public class UnknownContentEncodingException extends RuntimeException {
+
+ public UnknownContentEncodingException(String encoding) {
+ super("Unknown content encoding '" + encoding + "'");
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
index caee493e6f..942b88f1fb 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
@@ -9,6 +9,7 @@ import android.text.TextUtils;
import com.mapbox.mapboxsdk.BuildConfig;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.exceptions.UnknownContentEncodingException;
import java.io.IOException;
import java.io.InterruptedIOException;
@@ -66,7 +67,7 @@ class HTTPRequest implements Callback {
private native void nativeOnFailure(int type, String message);
private native void nativeOnResponse(int code, String etag, String modified, String cacheControl, String expires,
- String retryAfter, String xRateLimitReset, byte[] body);
+ String retryAfter, String xRateLimitReset, byte[] body, boolean gzip);
private HTTPRequest(long nativePtr, String resourceUrl, String etag, String modified) {
mNativePtr = nativePtr;
@@ -93,6 +94,7 @@ class HTTPRequest implements Callback {
Request.Builder builder = new Request.Builder()
.url(resourceUrl)
.tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE))
+ .addHeader("Accept-Encoding", "gzip, deflate")
.addHeader("User-Agent", getUserAgent());
if (etag.length() > 0) {
builder = builder.addHeader("If-None-Match", etag);
@@ -149,6 +151,18 @@ class HTTPRequest implements Callback {
mLock.lock();
if (mNativePtr != 0) {
+ String encoding = response.header("Content-Encoding");
+ boolean compressed = false;
+ if (encoding != null) {
+ if (encoding.equals("gzip") || encoding.equals("deflate")) {
+ compressed = true;
+ } else if (!encoding.equals("identity")) {
+ mLock.unlock();
+ handleFailure(call, new UnknownContentEncodingException(encoding));
+ return;
+ }
+ }
+
nativeOnResponse(response.code(),
response.header("ETag"),
response.header("Last-Modified"),
@@ -156,7 +170,8 @@ class HTTPRequest implements Callback {
response.header("Expires"),
response.header("Retry-After"),
response.header("x-rate-limit-reset"),
- body);
+ body,
+ compressed);
}
mLock.unlock();
}
diff --git a/platform/android/src/asset_manager_file_source.cpp b/platform/android/src/asset_manager_file_source.cpp
index aa65e3ff48..404177ba95 100644
--- a/platform/android/src/asset_manager_file_source.cpp
+++ b/platform/android/src/asset_manager_file_source.cpp
@@ -23,8 +23,9 @@ public:
Response response;
if (AAsset* asset = AAssetManager_open(assetManager, path.c_str(), AASSET_MODE_BUFFER)) {
- response.data = std::make_shared<std::string>(
- reinterpret_cast<const char*>(AAsset_getBuffer(asset)), AAsset_getLength64(asset));
+ response.data = { { reinterpret_cast<const char*>(AAsset_getBuffer(asset)),
+ static_cast<size_t>(AAsset_getLength64(asset)) },
+ false };
AAsset_close(asset);
} else {
response.error = std::make_unique<Response::Error>(Response::Error::Reason::NotFound,
diff --git a/platform/android/src/http_file_source.cpp b/platform/android/src/http_file_source.cpp
index 8eb9416e9d..7602c1914e 100644
--- a/platform/android/src/http_file_source.cpp
+++ b/platform/android/src/http_file_source.cpp
@@ -30,7 +30,8 @@ public:
jni::String etag, jni::String modified,
jni::String cacheControl, jni::String expires,
jni::String retryAfter, jni::String xRateLimitReset,
- jni::Array<jni::jbyte> body);
+ jni::Array<jni::jbyte> body,
+ jni::jboolean compressed);
static jni::Class<HTTPRequest> javaClass;
jni::UniqueObject<HTTPRequest> javaRequest;
@@ -104,7 +105,8 @@ void HTTPRequest::onResponse(jni::JNIEnv& env, int code,
jni::String etag, jni::String modified,
jni::String cacheControl, jni::String expires,
jni::String jRetryAfter, jni::String jXRateLimitReset,
- jni::Array<jni::jbyte> body) {
+ jni::Array<jni::jbyte> body,
+ jni::jboolean compressed) {
using Error = Response::Error;
@@ -128,11 +130,11 @@ void HTTPRequest::onResponse(jni::JNIEnv& env, int code,
if (code == 200) {
if (body) {
- auto data = std::make_shared<std::string>(body.Length(env), char());
- jni::GetArrayRegion(env, *body, 0, data->size(), reinterpret_cast<jbyte*>(&(*data)[0]));
- response.data = data;
+ std::string data(static_cast<size_t>(body.Length(env)), char());
+ jni::GetArrayRegion(env, *body, 0, data.size(), reinterpret_cast<jbyte*>(&data[0]));
+ response.data = Blob{ std::move(data), static_cast<bool>(compressed) };
} else {
- response.data = std::make_shared<std::string>();
+ response.data = {};
}
} else if (code == 204 || (code == 404 && resource.kind == Resource::Kind::Tile)) {
response.noContent = true;
diff --git a/platform/android/src/image.cpp b/platform/android/src/image.cpp
index 2a33944b18..dd98a3a6c8 100644
--- a/platform/android/src/image.cpp
+++ b/platform/android/src/image.cpp
@@ -8,14 +8,16 @@
namespace mbgl {
-PremultipliedImage decodeImage(const std::string& string) {
+PremultipliedImage decodeImage(Blob blob) {
auto env{ android::AttachEnv() };
- auto array = jni::Array<jni::jbyte>::New(*env, string.size());
- jni::SetArrayRegion(*env, *array, 0, string.size(),
- reinterpret_cast<const signed char*>(string.data()));
+ const auto string = blob.uncompressedData();
- auto bitmap = android::BitmapFactory::DecodeByteArray(*env, array, 0, string.size());
+ auto array = jni::Array<jni::jbyte>::New(*env, string->size());
+ jni::SetArrayRegion(*env, *array, 0, string->size(),
+ reinterpret_cast<const signed char*>(string->data()));
+
+ auto bitmap = android::BitmapFactory::DecodeByteArray(*env, array, 0, string->size());
return android::Bitmap::GetImage(*env, bitmap);
}
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 67fc132204..c52aad6405 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -188,11 +188,11 @@ void NativeMapView::setStyleUrl(jni::JNIEnv& env, jni::String url) {
}
jni::String NativeMapView::getStyleJson(jni::JNIEnv& env) {
- return jni::Make<jni::String>(env, map->getStyle().getJSON());
+ return jni::Make<jni::String>(env, *map->getStyle().getJSON().uncompressedData());
}
void NativeMapView::setStyleJson(jni::JNIEnv& env, jni::String json) {
- map->getStyle().loadJSON(jni::Make<std::string>(env, json));
+ map->getStyle().loadJSON(Blob{ jni::Make<std::string>(env, json), false });
}
void NativeMapView::setLatLngBounds(jni::JNIEnv& env, jni::Object<mbgl::android::LatLngBounds> jBounds) {
diff --git a/platform/darwin/src/http_file_source.mm b/platform/darwin/src/http_file_source.mm
index 4a16ad82fb..6840740c44 100644
--- a/platform/darwin/src/http_file_source.mm
+++ b/platform/darwin/src/http_file_source.mm
@@ -232,8 +232,7 @@ std::unique_ptr<AsyncRequest> HTTPFileSource::request(const Resource& resource,
if (error) {
if (data) {
- response.data =
- std::make_shared<std::string>((const char*)[data bytes], [data length]);
+ response.data = Blob{ { (const char*)[data bytes], [data length] }, false };
}
switch ([error code]) {
@@ -287,7 +286,7 @@ std::unique_ptr<AsyncRequest> HTTPFileSource::request(const Resource& resource,
}
if (responseCode == 200) {
- response.data = std::make_shared<std::string>((const char *)[data bytes], [data length]);
+ response.data = { { (const char *)[data bytes], [data length] }, false };
} else if (responseCode == 204 || (responseCode == 404 && resource.kind == Resource::Kind::Tile)) {
response.noContent = true;
} else if (responseCode == 304) {
diff --git a/platform/darwin/src/image.mm b/platform/darwin/src/image.mm
index 3a5adcca0a..f08fb9a25f 100644
--- a/platform/darwin/src/image.mm
+++ b/platform/darwin/src/image.mm
@@ -71,9 +71,10 @@ mbgl::PremultipliedImage MGLPremultipliedImageFromCGImage(CGImageRef src) {
namespace mbgl {
-PremultipliedImage decodeImage(const std::string& source) {
+PremultipliedImage decodeImage(Blob blob) {
+ const auto source = blob.uncompressedData();
CFDataHandle data(CFDataCreateWithBytesNoCopy(
- kCFAllocatorDefault, reinterpret_cast<const unsigned char*>(source.data()), source.size(),
+ kCFAllocatorDefault, reinterpret_cast<const unsigned char*>(source->data()), source->size(),
kCFAllocatorNull));
if (!data) {
throw std::runtime_error("CFDataCreateWithBytesNoCopy failed");
diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm
index 28c6633028..f0d54f81b4 100644
--- a/platform/darwin/test/MGLOfflineStorageTests.mm
+++ b/platform/darwin/test/MGLOfflineStorageTests.mm
@@ -182,8 +182,8 @@
req = fs->request(resource, [&](mbgl::Response res) {
req.reset();
XCTAssertFalse(res.error.get(), @"Request should not return an error");
- XCTAssertTrue(res.data.get(), @"Request should return data");
- XCTAssertEqual("{\"api\":\"mapbox\"}", *res.data, @"Request did not return expected data");
+ XCTAssertTrue(res.data, @"Request should return data");
+ XCTAssertEqual("{\"api\":\"mapbox\"}", *res.data.uncompressedData(), @"Request did not return expected data");
CFRunLoopStop(CFRunLoopGetCurrent());
});
diff --git a/platform/default/asset_file_source.cpp b/platform/default/asset_file_source.cpp
index 3063bf88a0..0b57a6dcef 100644
--- a/platform/default/asset_file_source.cpp
+++ b/platform/default/asset_file_source.cpp
@@ -44,12 +44,10 @@ public:
} else if (result == -1 && errno == ENOENT) {
response.error = std::make_unique<Response::Error>(Response::Error::Reason::NotFound);
} else {
- try {
- response.data = std::make_shared<std::string>(util::read_file(path));
- } catch (...) {
+ response.data = util::readFile(path);
+ if (!response.data) {
response.error = std::make_unique<Response::Error>(
- Response::Error::Reason::Other,
- util::toString(std::current_exception()));
+ Response::Error::Reason::Other, "Cannot read file " + path);
}
}
diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp
index cb602995a4..5dcd28facd 100644
--- a/platform/default/default_file_source.cpp
+++ b/platform/default/default_file_source.cpp
@@ -151,8 +151,23 @@ public:
// Get from the online file source
if (resource.hasLoadingMethod(Resource::LoadingMethod::Network)) {
+ // Always solicit a compressed response so that we can insert it into the database
+ // while still compressed to save on CPU time.
+ const auto compression = resource.compression;
+ resource.compression = Resource::Compression::PreferCompressed;
tasks[req] = onlineFileSource.request(resource, [=] (Response onlineResponse) mutable {
this->offlineDatabase->put(resource, onlineResponse);
+ // If the original request expects an uncompressed response, uncompress before
+ // handing it back.
+ if (onlineResponse.data && onlineResponse.data.isCompressed() &&
+ compression == Resource::Compression::Uncompressed) {
+ try {
+ onlineResponse.data.uncompress();
+ } catch (std::exception& ex) {
+ onlineResponse.error = std::make_unique<Response::Error>(
+ Response::Error::Reason::Other, ex.what());
+ }
+ }
callback(onlineResponse);
});
}
diff --git a/platform/default/http_file_source.cpp b/platform/default/http_file_source.cpp
index a9c442c2de..1a0ae577b8 100644
--- a/platform/default/http_file_source.cpp
+++ b/platform/default/http_file_source.cpp
@@ -371,9 +371,9 @@ void HTTPRequest::handleResult(CURLcode code) {
if (responseCode == 200) {
if (data) {
- response->data = std::move(data);
+ response->data = Blob{ std::move(data), false };
} else {
- response->data = std::make_shared<std::string>();
+ response->data = Blob{ "", false };
}
} else if (responseCode == 204 || (responseCode == 404 && resource.kind == Resource::Kind::Tile)) {
response->noContent = true;
diff --git a/platform/default/image.cpp b/platform/default/image.cpp
index 447c6bcd66..4fde1898c6 100644
--- a/platform/default/image.cpp
+++ b/platform/default/image.cpp
@@ -11,9 +11,10 @@ PremultipliedImage decodeWebP(const uint8_t*, size_t);
PremultipliedImage decodePNG(const uint8_t*, size_t);
PremultipliedImage decodeJPEG(const uint8_t*, size_t);
-PremultipliedImage decodeImage(const std::string& string) {
- const auto* data = reinterpret_cast<const uint8_t*>(string.data());
- const size_t size = string.size();
+PremultipliedImage decodeImage(Blob blob) {
+ const auto uncompressed = blob.uncompressedData();
+ const auto* data = reinterpret_cast<const uint8_t*>(uncompressed->data());
+ const size_t size = uncompressed->size();
#if !defined(__ANDROID__) && !defined(__APPLE__)
if (size >= 12) {
diff --git a/platform/default/local_file_source.cpp b/platform/default/local_file_source.cpp
index 0635e86d80..9a8f5ae51b 100644
--- a/platform/default/local_file_source.cpp
+++ b/platform/default/local_file_source.cpp
@@ -46,12 +46,10 @@ public:
} else if (result == -1 && errno == ENOENT) {
response.error = std::make_unique<Response::Error>(Response::Error::Reason::NotFound);
} else {
- try {
- response.data = std::make_shared<std::string>(util::read_file(path));
- } catch (...) {
+ response.data = util::readFile(path);
+ if (!response.data) {
response.error = std::make_unique<Response::Error>(
- Response::Error::Reason::Other,
- util::toString(std::current_exception()));
+ Response::Error::Reason::Other, "Cannot read file " + path);
}
}
diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp
index 65c2097182..d7022f1c80 100644
--- a/platform/default/mbgl/storage/offline_database.cpp
+++ b/platform/default/mbgl/storage/offline_database.cpp
@@ -1,10 +1,10 @@
#include <mbgl/storage/offline_database.hpp>
#include <mbgl/storage/response.hpp>
-#include <mbgl/util/compression.hpp>
#include <mbgl/util/io.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/logging.hpp>
+#include <mbgl/util/compression.hpp>
#include "sqlite3.hpp"
@@ -153,7 +153,7 @@ optional<Response> OfflineDatabase::get(const Resource& resource) {
optional<std::pair<Response, uint64_t>> OfflineDatabase::getInternal(const Resource& resource) {
if (resource.kind == Resource::Kind::Tile) {
assert(resource.tileData);
- return getTile(*resource.tileData);
+ return getTile(resource);
} else {
return getResource(resource);
}
@@ -177,14 +177,31 @@ std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource,
return { false, 0 };
}
- std::string compressedData;
+ std::shared_ptr<const std::string> data;
bool compressed = false;
uint64_t size = 0;
if (response.data) {
- compressedData = util::compress(*response.data);
- compressed = compressedData.size() < response.data->size();
- size = compressed ? compressedData.size() : response.data->size();
+ if (response.data.isCompressed()) {
+ // The response is already compressed; don't try to compare it against the uncompressed size.
+ compressed = true;
+ data = response.data.compressedData();
+ } else {
+ data = response.data.uncompressedData();
+
+ // Only try to compress the data when we have a good chance that the data can actually
+ // be considerably compressed.
+ if (util::isCompressible(*data)) {
+ const auto compressedData = response.data.compressedData();
+ if (compressedData->size() < data->size()) {
+ compressed = true;
+ data = compressedData;
+ }
+ }
+ }
+ size = data->size();
+ } else {
+ data = std::make_shared<const std::string>();
}
if (evict_ && !evict(size)) {
@@ -196,13 +213,9 @@ std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource,
if (resource.kind == Resource::Kind::Tile) {
assert(resource.tileData);
- inserted = putTile(*resource.tileData, response,
- compressed ? compressedData : response.data ? *response.data : "",
- compressed);
+ inserted = putTile(*resource.tileData, response, *data, compressed);
} else {
- inserted = putResource(resource, response,
- compressed ? compressedData : response.data ? *response.data : "",
- compressed);
+ inserted = putResource(resource, response, *data, compressed);
}
return { inserted, size };
@@ -243,12 +256,20 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resou
optional<std::string> data = stmt->get<optional<std::string>>(4);
if (!data) {
response.noContent = true;
- } else if (stmt->get<bool>(5)) {
- response.data = std::make_shared<std::string>(util::decompress(*data));
- size = data->length();
} else {
- response.data = std::make_shared<std::string>(*data);
+ response.data = { std::move(*data), stmt->get<bool>(5) };
size = data->length();
+
+ // Make sure the data is decompressed when the user explicitly requested uncompressed data.
+ if (response.data.isCompressed() &&
+ resource.compression == Resource::Compression::Uncompressed) {
+ try {
+ response.data.uncompress();
+ } catch (std::exception& ex) {
+ response.error =
+ std::make_unique<Response::Error>(Response::Error::Reason::Other, ex.what());
+ }
+ }
}
return std::make_pair(response, size);
@@ -359,7 +380,9 @@ bool OfflineDatabase::putResource(const Resource& resource,
return true;
}
-optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource::TileData& tile) {
+optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource& resource) {
+ const auto& tile = *resource.tileData;
+
// clang-format off
Statement accessedStmt = getStatement(
"UPDATE tiles "
@@ -412,12 +435,20 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource:
optional<std::string> data = stmt->get<optional<std::string>>(4);
if (!data) {
response.noContent = true;
- } else if (stmt->get<bool>(5)) {
- response.data = std::make_shared<std::string>(util::decompress(*data));
- size = data->length();
} else {
- response.data = std::make_shared<std::string>(*data);
+ response.data = { std::move(*data), stmt->get<bool>(5) };
size = data->length();
+
+ // Make sure the data is decompressed when the user explicitly requested uncompressed data.
+ if (response.data.isCompressed() &&
+ resource.compression == Resource::Compression::Uncompressed) {
+ try {
+ response.data.uncompress();
+ } catch (std::exception& ex) {
+ response.error =
+ std::make_unique<Response::Error>(Response::Error::Reason::Other, ex.what());
+ }
+ }
}
return std::make_pair(response, size);
diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp
index 91b544a9e0..fba1a3c230 100644
--- a/platform/default/mbgl/storage/offline_database.hpp
+++ b/platform/default/mbgl/storage/offline_database.hpp
@@ -81,7 +81,7 @@ private:
Statement getStatement(const char *);
- optional<std::pair<Response, uint64_t>> getTile(const Resource::TileData&);
+ optional<std::pair<Response, uint64_t>> getTile(const Resource&);
optional<int64_t> hasTile(const Resource::TileData&);
bool putTile(const Resource::TileData&, const Response&,
const std::string&, bool compressed);
diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp
index ba504c1f9b..d8fe8c646b 100644
--- a/platform/default/mbgl/storage/offline_download.cpp
+++ b/platform/default/mbgl/storage/offline_download.cpp
@@ -71,7 +71,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
}
style::Parser parser;
- parser.parse(*styleResponse->data);
+ parser.parse(*styleResponse->data.uncompressedData());
result.requiredResourceCountIsPrecise = true;
@@ -88,7 +88,8 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
optional<Response> sourceResponse = offlineDatabase.get(Resource::source(url));
if (sourceResponse) {
style::conversion::Error error;
- optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(*sourceResponse->data, error);
+ optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(
+ *sourceResponse->data.uncompressedData(), error);
if (tileset) {
result.requiredResourceCount +=
definition.tileCount(type, tileSize, (*tileset).zoomRange);
@@ -160,7 +161,7 @@ void OfflineDownload::activateDownload() {
status.requiredResourceCountIsPrecise = true;
style::Parser parser;
- parser.parse(*styleResponse.data);
+ parser.parse(*styleResponse.data.uncompressedData());
for (const auto& source : parser.sources) {
SourceType type = source->getType();
@@ -176,7 +177,8 @@ void OfflineDownload::activateDownload() {
ensureResource(Resource::source(url), [=](Response sourceResponse) {
style::conversion::Error error;
- optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(*sourceResponse.data, error);
+ optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(
+ *sourceResponse.data.uncompressedData(), error);
if (tileset) {
util::mapbox::canonicalizeTileset(*tileset, url, type, tileSize);
queueTiles(type, tileSize, *tileset);
@@ -236,14 +238,18 @@ void OfflineDownload::activateDownload() {
if (!parser.glyphURL.empty()) {
for (const auto& fontStack : parser.fontStacks()) {
for (char16_t i = 0; i < GLYPH_RANGES_PER_FONT_STACK; i++) {
- queueResource(Resource::glyphs(parser.glyphURL, fontStack, getGlyphRange(i * GLYPHS_PER_GLYPH_RANGE)));
+ auto resource = Resource::glyphs(parser.glyphURL, fontStack, getGlyphRange(i * GLYPHS_PER_GLYPH_RANGE));
+ resource.compression = Resource::Compression::PreferCompressed;
+ queueResource(resource);
}
}
}
if (!parser.spriteURL.empty()) {
queueResource(Resource::spriteImage(parser.spriteURL, definition.pixelRatio));
- queueResource(Resource::spriteJSON(parser.spriteURL, definition.pixelRatio));
+ auto spriteJSON = Resource::spriteJSON(parser.spriteURL, definition.pixelRatio);
+ spriteJSON.compression = Resource::Compression::PreferCompressed;
+ queueResource(spriteJSON);
}
continueDownload();
diff --git a/platform/default/online_file_source.cpp b/platform/default/online_file_source.cpp
index d685109b95..fe77df8c02 100644
--- a/platform/default/online_file_source.cpp
+++ b/platform/default/online_file_source.cpp
@@ -374,6 +374,16 @@ void OnlineFileRequest::completed(Response response) {
failedRequestReason = Response::Error::Reason::Success;
}
+ // Make sure the data is decompressed when the user explicitly requested uncompressed data.
+ if (response.data && response.data.isCompressed() &&
+ resource.compression == Resource::Compression::Uncompressed) {
+ try {
+ response.data.uncompress();
+ } catch (std::exception& ex) {
+ response.error = std::make_unique<Response::Error>(Response::Error::Reason::Other, ex.what());
+ }
+ }
+
schedule(response.expires);
// Calling the callback may result in `this` being deleted. It needs to be done last,
diff --git a/platform/default/png_writer.cpp b/platform/default/png_writer.cpp
index 9ef9052158..d3297b8ebf 100644
--- a/platform/default/png_writer.cpp
+++ b/platform/default/png_writer.cpp
@@ -38,7 +38,7 @@ void addChunk(std::string& png, const char* type, const char* data = "", const u
namespace mbgl {
// Encode PNGs without libpng.
-std::string encodePNG(const PremultipliedImage& pre) {
+Blob encodePNG(const PremultipliedImage& pre) {
// Make copy of the image so that we can unpremultiply it.
const auto src = util::unpremultiply(pre.clone());
@@ -74,7 +74,7 @@ std::string encodePNG(const PremultipliedImage& pre) {
addChunk(png, "IHDR", ihdr, 13);
addChunk(png, "IDAT", idat.data(), static_cast<uint32_t>(idat.size()));
addChunk(png, "IEND");
- return png;
+ return { std::move(png), false };
}
} // namespace mbgl
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 07fae5945c..c29c2ec89f 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -211,6 +211,7 @@
40F887701D7A1E58008ECB67 /* MGLShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */; };
40F887711D7A1E59008ECB67 /* MGLShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */; };
40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */; };
+ 55434256203C7530002624EB /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55434255203C7530002624EB /* libz.tbd */; };
5549A0381EF1D86B00073113 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5549A0371EF1D86B00073113 /* libmbgl-core.a */; };
5549A0391EF2877100073113 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 554180411D2E97DE00012372 /* OpenGLES.framework */; };
5549A03A1EF2877500073113 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 554180411D2E97DE00012372 /* OpenGLES.framework */; };
@@ -794,6 +795,7 @@
40FDA7691CCAAA6800442548 /* MBXAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXAnnotationView.h; sourceTree = "<group>"; };
40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXAnnotationView.m; sourceTree = "<group>"; };
554180411D2E97DE00012372 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
+ 55434255203C7530002624EB /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
5549A0371EF1D86B00073113 /* libmbgl-core.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-core.a"; path = "../../build/ios/Debug-iphonesimulator/libmbgl-core.a"; sourceTree = "<group>"; };
556660C91E1BF3A900E2C41B /* MGLFoundation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLFoundation.h; sourceTree = "<group>"; };
556660D71E1D085500E2C41B /* MGLVersionNumber.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLVersionNumber.m; path = ../../darwin/test/MGLVersionNumber.m; sourceTree = "<group>"; };
@@ -1145,6 +1147,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 55434256203C7530002624EB /* libz.tbd in Frameworks */,
5549A0381EF1D86B00073113 /* libmbgl-core.a in Frameworks */,
DA2E88561CC036F400F24E7B /* Mapbox.framework in Frameworks */,
);
@@ -1477,6 +1480,7 @@
DA1DC9921CB6DF24006E619F /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 55434255203C7530002624EB /* libz.tbd */,
55D120AD1F791018004B6D81 /* libmbgl-loop-darwin.a */,
55D120AB1F791015004B6D81 /* libmbgl-filesource.a */,
55D120A91F79100C004B6D81 /* libmbgl-filesource.a */,
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 4327670911..58f29ed2a3 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -80,6 +80,7 @@
52B5D17F1E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */; };
52B5D1801E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */; };
5548BE781D09E718005DDE81 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; };
+ 555CF3EC203DA46F004C828F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D9B4B01D005D3900C1CCE2 /* libz.tbd */; };
556660C61E1BEA0100E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C51E1BEA0100E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
556660D61E1D07E400E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D51E1D07E400E2C41B /* MGLVersionNumber.m */; };
558DE7A61E56161C00C7916D /* MGLFoundation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 558DE7A41E56161C00C7916D /* MGLFoundation_Private.h */; };
@@ -659,6 +660,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 555CF3EC203DA46F004C828F /* libz.tbd in Frameworks */,
DAE0DD7A1D5F015A005A6BB1 /* libmbgl-core.a in Frameworks */,
55D120A51F790A0C004B6D81 /* libmbgl-filesource.a in Frameworks */,
DAE6C3321CC30DB200DB3429 /* Mapbox.framework in Frameworks */,
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index ac14df0228..a4f6f6a9de 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -214,8 +214,8 @@ void NodeMap::Load(const Nan::FunctionCallbackInfo<v8::Value>& info) {
}
try {
- nodeMap->map->getStyle().loadJSON(style);
- } catch (const std::exception &ex) {
+ nodeMap->map->getStyle().loadJSON(mbgl::Blob{ std::move(style), false });
+ } catch (const std::exception& ex) {
return Nan::ThrowError(ex.what());
}
diff --git a/platform/node/src/node_request.cpp b/platform/node/src/node_request.cpp
index de16710f78..7b2b57fd1f 100644
--- a/platform/node/src/node_request.cpp
+++ b/platform/node/src/node_request.cpp
@@ -99,10 +99,8 @@ void NodeRequest::HandleCallback(const Nan::FunctionCallbackInfo<v8::Value>& inf
if (Nan::Has(res, Nan::New("data").ToLocalChecked()).FromJust()) {
auto data = Nan::Get(res, Nan::New("data").ToLocalChecked()).ToLocalChecked();
if (node::Buffer::HasInstance(data)) {
- response.data = std::make_shared<std::string>(
- node::Buffer::Data(data),
- node::Buffer::Length(data)
- );
+ response.data = { std::string{ node::Buffer::Data(data), node::Buffer::Length(data), },
+ false };
} else {
return Nan::ThrowTypeError("Response data must be a Buffer");
}
diff --git a/platform/qt/src/http_request.cpp b/platform/qt/src/http_request.cpp
index ea3f388bd5..4e2143ba8e 100644
--- a/platform/qt/src/http_request.cpp
+++ b/platform/qt/src/http_request.cpp
@@ -99,9 +99,9 @@ void HTTPRequest::handleNetworkReply(QNetworkReply *reply, const QByteArray& dat
switch(responseCode) {
case 200: {
if (data.isEmpty()) {
- response.data = std::make_shared<std::string>();
+ response.data = Blob{ "", false };
} else {
- response.data = std::make_shared<std::string>(data.constData(), data.size());
+ response.data = Blob{ std::string{ data.constData(), static_cast<size_t>(data.size()) }, false };
}
break;
}
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index 414b65255c..e054d88489 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -585,12 +585,12 @@ void QMapboxGL::cycleDebugOptions()
*/
QString QMapboxGL::styleJson() const
{
- return QString::fromStdString(d_ptr->mapObj->getStyle().getJSON());
+ return QString::fromStdString(*d_ptr->mapObj->getStyle().getJSON().uncompressedData());
}
void QMapboxGL::setStyleJson(const QString &style)
{
- d_ptr->mapObj->getStyle().loadJSON(style.toStdString());
+ d_ptr->mapObj->getStyle().loadJSON(mbgl::Blob{ style.toStdString(), false });
}
/*!
diff --git a/platform/qt/src/qt_image.cpp b/platform/qt/src/qt_image.cpp
index a5c92514c1..ff45b02ef1 100644
--- a/platform/qt/src/qt_image.cpp
+++ b/platform/qt/src/qt_image.cpp
@@ -6,7 +6,7 @@
namespace mbgl {
-std::string encodePNG(const PremultipliedImage& pre) {
+Blob encodePNG(const PremultipliedImage& pre) {
QImage image(pre.data.get(), pre.size.width, pre.size.height,
QImage::Format_ARGB32_Premultiplied);
@@ -16,7 +16,7 @@ std::string encodePNG(const PremultipliedImage& pre) {
buffer.open(QIODevice::WriteOnly);
image.rgbSwapped().save(&buffer, "PNG");
- return std::string(array.constData(), array.size());
+ return { std::string(array.constData(), array.size()), false };
}
#if !defined(QT_IMAGE_DECODERS)
@@ -24,9 +24,10 @@ PremultipliedImage decodeJPEG(const uint8_t*, size_t);
PremultipliedImage decodeWebP(const uint8_t*, size_t);
#endif
-PremultipliedImage decodeImage(const std::string& string) {
- const uint8_t* data = reinterpret_cast<const uint8_t*>(string.data());
- const size_t size = string.size();
+PremultipliedImage decodeImage(Blob blob) {
+ const auto uncompressed = blob.uncompressedData();
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(uncompressed->data());
+ const size_t size = uncompressed->size();
#if !defined(QT_IMAGE_DECODERS)
if (size >= 12) {
diff --git a/platform/qt/test/qmapboxgl.test.cpp b/platform/qt/test/qmapboxgl.test.cpp
index 2a56b346a3..607cdd6ba9 100644
--- a/platform/qt/test/qmapboxgl.test.cpp
+++ b/platform/qt/test/qmapboxgl.test.cpp
@@ -47,7 +47,7 @@ void QMapboxGLTest::onNeedsRendering() {
TEST_F(QMapboxGLTest, TEST_DISABLED_ON_CI(styleJson)) {
QString json = QString::fromStdString(
- mbgl::util::read_file("test/fixtures/resources/style_vector.json"));
+ *mbgl::util::readFile("test/fixtures/resources/style_vector.json").uncompressedData());
map.setStyleJson(json);
ASSERT_EQ(map.styleJson(), json);