summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/geometry/glyph_atlas.cpp13
-rw-r--r--src/mbgl/geometry/line_atlas.cpp3
-rw-r--r--src/mbgl/geometry/sprite_atlas.cpp20
-rw-r--r--src/mbgl/map/annotation.cpp5
-rw-r--r--src/mbgl/map/annotation.hpp1
-rw-r--r--src/mbgl/map/map.cpp16
-rw-r--r--src/mbgl/map/map_context.cpp39
-rw-r--r--src/mbgl/map/map_context.hpp3
-rw-r--r--src/mbgl/map/map_data.hpp10
-rw-r--r--src/mbgl/map/resource_loader.cpp41
-rw-r--r--src/mbgl/map/resource_loader.hpp10
-rw-r--r--src/mbgl/map/source.cpp61
-rw-r--r--src/mbgl/map/source.hpp9
-rw-r--r--src/mbgl/map/sprite.cpp62
-rw-r--r--src/mbgl/map/sprite.hpp6
-rw-r--r--src/mbgl/map/tile_data.cpp22
-rw-r--r--src/mbgl/map/tile_data.hpp13
-rw-r--r--src/mbgl/map/tile_parser.cpp7
-rw-r--r--src/mbgl/map/transform.cpp2
-rw-r--r--src/mbgl/map/vector_tile_data.cpp9
-rw-r--r--src/mbgl/renderer/fill_bucket.cpp5
-rw-r--r--src/mbgl/renderer/line_bucket.cpp3
-rw-r--r--src/mbgl/renderer/painter.cpp27
-rw-r--r--src/mbgl/renderer/painter_fill.cpp1
-rw-r--r--src/mbgl/renderer/painter_raster.cpp1
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp11
-rw-r--r--src/mbgl/shader/shader.cpp6
-rw-r--r--src/mbgl/storage/default_file_source.cpp27
-rw-r--r--src/mbgl/storage/request.cpp5
-rw-r--r--src/mbgl/style/style.cpp3
-rw-r--r--src/mbgl/style/style_parser.cpp1
-rw-r--r--src/mbgl/text/font_stack.cpp140
-rw-r--r--src/mbgl/text/font_stack.hpp28
-rw-r--r--src/mbgl/text/glyph.hpp14
-rw-r--r--src/mbgl/text/glyph_pbf.cpp115
-rw-r--r--src/mbgl/text/glyph_pbf.hpp52
-rw-r--r--src/mbgl/text/glyph_store.cpp309
-rw-r--r--src/mbgl/text/glyph_store.hpp85
-rw-r--r--src/mbgl/util/raster.cpp3
-rw-r--r--src/mbgl/util/run_loop.hpp70
-rw-r--r--src/mbgl/util/thread.hpp40
-rw-r--r--src/mbgl/util/worker.cpp4
42 files changed, 752 insertions, 550 deletions
diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp
index bb230e4efd..067c5a4062 100644
--- a/src/mbgl/geometry/glyph_atlas.cpp
+++ b/src/mbgl/geometry/glyph_atlas.cpp
@@ -1,11 +1,11 @@
#include <mbgl/geometry/glyph_atlas.hpp>
+#include <mbgl/text/font_stack.hpp>
+
#include <mbgl/platform/gl.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
-#include <mbgl/util/std.hpp>
-
#include <cassert>
#include <algorithm>
@@ -16,7 +16,7 @@ GlyphAtlas::GlyphAtlas(uint16_t width_, uint16_t height_)
: width(width_),
height(height_),
bin(width_, height_),
- data(util::make_unique<uint8_t[]>(width_ * height_)),
+ data(std::make_unique<uint8_t[]>(width_ * height_)),
dirty(true) {
}
@@ -69,8 +69,9 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
uint16_t buffered_height = glyph.metrics.height + buffer * 2;
// Add a 1px border around every image.
- uint16_t pack_width = buffered_width;
- uint16_t pack_height = buffered_height;
+ const uint16_t padding = 1;
+ uint16_t pack_width = buffered_width + 2 * padding;
+ uint16_t pack_height = buffered_height + 2 * padding;
// Increase to next number divisible by 4, but at least 1.
// This is so we can scale down the texture coordinates and pack them
@@ -92,7 +93,7 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
// Copy the bitmap
const uint8_t* source = reinterpret_cast<const uint8_t*>(glyph.bitmap.data());
for (uint32_t y = 0; y < buffered_height; y++) {
- uint32_t y1 = width * (rect.y + y) + rect.x;
+ uint32_t y1 = width * (rect.y + y + padding) + rect.x + padding;
uint32_t y2 = buffered_width * y;
for (uint32_t x = 0; x < buffered_width; x++) {
data[y1 + x] = source[y2 + x];
diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp
index 91ac15639b..dc5ee0901a 100644
--- a/src/mbgl/geometry/line_atlas.cpp
+++ b/src/mbgl/geometry/line_atlas.cpp
@@ -3,7 +3,6 @@
#include <mbgl/platform/gl.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
-#include <mbgl/util/std.hpp>
#include <boost/functional/hash.hpp>
@@ -15,7 +14,7 @@ using namespace mbgl;
LineAtlas::LineAtlas(uint16_t w, uint16_t h)
: width(w),
height(h),
- data(util::make_unique<uint8_t[]>(w * h)),
+ data(std::make_unique<uint8_t[]>(w * h)),
dirty(true) {
}
diff --git a/src/mbgl/geometry/sprite_atlas.cpp b/src/mbgl/geometry/sprite_atlas.cpp
index 5d47793cf5..93bc76aa5c 100644
--- a/src/mbgl/geometry/sprite_atlas.cpp
+++ b/src/mbgl/geometry/sprite_atlas.cpp
@@ -127,10 +127,12 @@ SpriteAtlasPosition SpriteAtlas::getPosition(const std::string& name, bool repea
rect.h = pos.height / pos.pixelRatio;
}
+ const float padding = 1;
+
return SpriteAtlasPosition {
{{ float(rect.w), float(rect.h) }},
- {{ float(rect.x) / width, float(rect.y) / height }},
- {{ float(rect.x + rect.w) / width, float(rect.y + rect.h) / height }}
+ {{ float(rect.x + padding) / width, float(rect.y + padding) / height }},
+ {{ float(rect.x + padding + rect.w) / width, float(rect.y + padding + rect.h) / height }}
};
}
@@ -138,7 +140,7 @@ void SpriteAtlas::allocate() {
if (!data) {
dimension w = static_cast<dimension>(width * pixelRatio);
dimension h = static_cast<dimension>(height * pixelRatio);
- data = util::make_unique<uint32_t[]>(w * h);
+ data = std::make_unique<uint32_t[]>(w * h);
std::fill(data.get(), data.get() + w * h, 0);
}
}
@@ -151,12 +153,14 @@ void SpriteAtlas::copy(const Rect<dimension>& dst, const SpritePosition& src, co
const vec2<uint32_t> srcSize { sprite->raster->getWidth(), sprite->raster->getHeight() };
const Rect<uint32_t> srcPos { src.x, src.y, src.width, src.height };
+ const int offset = 1;
+
allocate();
uint32_t *const dstData = data.get();
const vec2<uint32_t> dstSize { static_cast<unsigned int>(width * pixelRatio),
static_cast<unsigned int>(height * pixelRatio) };
- const Rect<uint32_t> dstPos { static_cast<uint32_t>(dst.x * pixelRatio),
- static_cast<uint32_t>(dst.y * pixelRatio),
+ const Rect<uint32_t> dstPos { static_cast<uint32_t>((offset + dst.x) * pixelRatio),
+ static_cast<uint32_t>((offset + dst.y) * pixelRatio),
static_cast<uint32_t>(dst.originalW * pixelRatio),
static_cast<uint32_t>(dst.originalH * pixelRatio) };
@@ -295,6 +299,8 @@ void SpriteAtlas::bind(bool linear) {
SpriteAtlas::~SpriteAtlas() {
std::lock_guard<std::recursive_mutex> lock(mtx);
- Environment::Get().abandonTexture(texture);
- texture = 0;
+ if (texture) {
+ Environment::Get().abandonTexture(texture);
+ texture = 0;
+ }
}
diff --git a/src/mbgl/map/annotation.cpp b/src/mbgl/map/annotation.cpp
index 9d21b4e48b..6df49ec647 100644
--- a/src/mbgl/map/annotation.cpp
+++ b/src/mbgl/map/annotation.cpp
@@ -5,7 +5,6 @@
#include <mbgl/map/map_data.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/ptr.hpp>
-#include <mbgl/util/std.hpp>
#include <algorithm>
#include <memory>
@@ -110,7 +109,7 @@ AnnotationManager::addPointAnnotations(const std::vector<LatLng>& points,
// track the annotation global ID and its geometry
auto anno_it = annotations.emplace(
annotationID,
- util::make_unique<Annotation>(AnnotationType::Point,
+ std::make_unique<Annotation>(AnnotationType::Point,
AnnotationSegments({ { points[i] } })));
const uint8_t maxZoom = data.transform.getMaxZoom();
@@ -162,7 +161,7 @@ AnnotationManager::addPointAnnotations(const std::vector<LatLng>& points,
// create tile & record annotation association
auto tile_pos = tiles.emplace(
tileID, std::make_pair(std::unordered_set<uint32_t>({ annotationID }),
- util::make_unique<LiveTile>()));
+ std::make_unique<LiveTile>()));
// add point layer to tile
tile_pos.first->second.second->addLayer(layerID, layer);
}
diff --git a/src/mbgl/map/annotation.hpp b/src/mbgl/map/annotation.hpp
index a80b03226f..0c9a078e57 100644
--- a/src/mbgl/map/annotation.hpp
+++ b/src/mbgl/map/annotation.hpp
@@ -4,7 +4,6 @@
#include <mbgl/map/tile_id.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/vec.hpp>
#include <string>
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 3ba82252de..0479189300 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -3,15 +3,14 @@
#include <mbgl/map/view.hpp>
#include <mbgl/map/map_data.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/projection.hpp>
#include <mbgl/util/thread.hpp>
namespace mbgl {
Map::Map(View& view, FileSource& fileSource, MapMode mode)
- : data(util::make_unique<MapData>(view, mode)),
- context(util::make_unique<util::Thread<MapContext>>("Map", util::ThreadPriority::Regular, view, fileSource, *data))
+ : data(std::make_unique<MapData>(view, mode)),
+ context(std::make_unique<util::Thread<MapContext>>("Map", util::ThreadPriority::Regular, view, fileSource, *data))
{
view.initialize(this);
}
@@ -195,17 +194,6 @@ void Map::resetNorth() {
}
-#pragma mark - Access Token
-
-void Map::setAccessToken(const std::string &token) {
- data->setAccessToken(token);
-}
-
-std::string Map::getAccessToken() const {
- return data->getAccessToken();
-}
-
-
#pragma mark - Projection
void Map::getWorldBoundsMeters(ProjectedMeters& sw, ProjectedMeters& ne) const {
diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp
index f373274ebd..c8948097f7 100644
--- a/src/mbgl/map/map_context.cpp
+++ b/src/mbgl/map/map_context.cpp
@@ -20,11 +20,9 @@
#include <mbgl/style/style.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/util/worker.hpp>
#include <mbgl/util/texture_pool.hpp>
-#include <mbgl/util/mapbox.hpp>
#include <mbgl/util/exception.hpp>
namespace mbgl {
@@ -35,12 +33,12 @@ MapContext::MapContext(uv_loop_t* loop, View& view_, FileSource& fileSource, Map
env(fileSource),
envScope(env, ThreadType::Map, "Map"),
updated(static_cast<UpdateType>(Update::Nothing)),
- asyncUpdate(util::make_unique<uv::async>(loop, [this] { update(); })),
- glyphStore(util::make_unique<GlyphStore>(loop, env)),
- glyphAtlas(util::make_unique<GlyphAtlas>(1024, 1024)),
- spriteAtlas(util::make_unique<SpriteAtlas>(512, 512)),
- lineAtlas(util::make_unique<LineAtlas>(512, 512)),
- texturePool(util::make_unique<TexturePool>()) {
+ asyncUpdate(std::make_unique<uv::async>(loop, [this] { update(); })),
+ glyphStore(std::make_unique<GlyphStore>(loop, env)),
+ glyphAtlas(std::make_unique<GlyphAtlas>(1024, 1024)),
+ spriteAtlas(std::make_unique<SpriteAtlas>(512, 512)),
+ lineAtlas(std::make_unique<LineAtlas>(512, 512)),
+ texturePool(std::make_unique<TexturePool>()) {
assert(Environment::currentlyOn(ThreadType::Map));
asyncUpdate->unref();
@@ -90,7 +88,7 @@ void MapContext::triggerUpdate(const Update u) {
}
void MapContext::setStyleURL(const std::string& url) {
- styleURL = mbgl::util::mapbox::normalizeStyleURL(url, data.getAccessToken());
+ styleURL = url;
styleJSON.clear();
const size_t pos = styleURL.rfind('/');
@@ -99,7 +97,7 @@ void MapContext::setStyleURL(const std::string& url) {
base = styleURL.substr(0, pos + 1);
}
- env.request({ Resource::Kind::JSON, styleURL }, [this, base](const Response &res) {
+ env.request({ Resource::Kind::Style, styleURL }, [this, base](const Response &res) {
if (res.status == Response::Successful) {
loadStyleJSON(res.data, base);
} else {
@@ -121,17 +119,15 @@ void MapContext::loadStyleJSON(const std::string& json, const std::string& base)
resourceLoader.reset();
style.reset();
- style = util::make_unique<Style>();
+ style = std::make_unique<Style>();
style->base = base;
style->loadJSON((const uint8_t *)json.c_str());
style->cascade(data.getClasses());
style->setDefaultTransitionDuration(data.getDefaultTransitionDuration());
- const std::string glyphURL = util::mapbox::normalizeGlyphsURL(style->glyph_url, data.getAccessToken());
- glyphStore->setURL(glyphURL);
+ glyphStore->setURL(style->glyph_url);
- resourceLoader = util::make_unique<ResourceLoader>();
- resourceLoader->setAccessToken(data.getAccessToken());
+ resourceLoader = std::make_unique<ResourceLoader>();
resourceLoader->setObserver(this);
resourceLoader->setStyle(style.get());
resourceLoader->setGlyphStore(glyphStore.get());
@@ -224,7 +220,7 @@ void MapContext::render() {
assert(style);
if (!painter) {
- painter = util::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas);
+ painter = std::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas);
painter->setup();
}
@@ -232,7 +228,7 @@ void MapContext::render() {
painter->render(*style, transformState, data.getAnimationTime());
if (data.mode == MapMode::Still) {
- callback(view.readStillImage());
+ callback(nullptr, view.readStillImage());
callback = nullptr;
}
@@ -274,4 +270,13 @@ void MapContext::onTileDataChanged() {
triggerUpdate();
}
+void MapContext::onResourceLoadingFailed(std::exception_ptr error) {
+ assert(Environment::currentlyOn(ThreadType::Map));
+
+ if (data.mode == MapMode::Still && callback) {
+ callback(error, nullptr);
+ callback = nullptr;
+ }
+}
+
}
diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp
index c842454849..fb9fdb4d4b 100644
--- a/src/mbgl/map/map_context.hpp
+++ b/src/mbgl/map/map_context.hpp
@@ -43,7 +43,7 @@ public:
void resize(uint16_t width, uint16_t height, float ratio);
- using StillImageCallback = std::function<void(std::unique_ptr<const StillImage>)>;
+ using StillImageCallback = std::function<void(std::exception_ptr, std::unique_ptr<const StillImage>)>;
void renderStill(StillImageCallback callback);
void triggerUpdate(Update = Update::Nothing);
@@ -61,6 +61,7 @@ public:
// ResourceLoader::Observer implementation.
void onTileDataChanged() override;
+ void onResourceLoadingFailed(std::exception_ptr error) override;
private:
void updateTiles();
diff --git a/src/mbgl/map/map_data.hpp b/src/mbgl/map/map_data.hpp
index 803a9b1acb..32722d07e8 100644
--- a/src/mbgl/map/map_data.hpp
+++ b/src/mbgl/map/map_data.hpp
@@ -27,15 +27,6 @@ public:
setDefaultTransitionDuration(Duration::zero());
}
- inline std::string getAccessToken() const {
- Lock lock(mtx);
- return accessToken;
- }
- inline void setAccessToken(const std::string &token) {
- Lock lock(mtx);
- accessToken = token;
- }
-
// Adds the class if it's not yet set. Returns true when it added the class, and false when it
// was already present.
bool addClass(const std::string& klass);
@@ -105,7 +96,6 @@ public:
private:
mutable std::mutex mtx;
- std::string accessToken;
std::vector<std::string> classes;
std::atomic<uint8_t> debug { false };
std::atomic<uint8_t> collisionDebug { false };
diff --git a/src/mbgl/map/resource_loader.cpp b/src/mbgl/map/resource_loader.cpp
index 2be86dc5e2..8e054c0d82 100644
--- a/src/mbgl/map/resource_loader.cpp
+++ b/src/mbgl/map/resource_loader.cpp
@@ -45,7 +45,7 @@ void ResourceLoader::setStyle(Style* style) {
for (const auto& source : style->sources) {
source->setObserver(this);
- source->load(accessToken_);
+ source->load();
}
}
@@ -60,11 +60,6 @@ void ResourceLoader::setGlyphStore(GlyphStore* glyphStore) {
glyphStore_->setObserver(this);
}
-
-void ResourceLoader::setAccessToken(const std::string& accessToken) {
- accessToken_ = accessToken;
-}
-
void ResourceLoader::update(MapData& data,
const TransformState& transform,
GlyphAtlas& glyphAtlas,
@@ -76,7 +71,7 @@ void ResourceLoader::update(MapData& data,
const float pixelRatio = transform.getPixelRatio();
if (!sprite_ || !sprite_->hasPixelRatio(pixelRatio)) {
- sprite_ = util::make_unique<Sprite>(style_->getSpriteURL(), pixelRatio);
+ sprite_ = std::make_unique<Sprite>(style_->getSpriteURL(), pixelRatio);
sprite_->setObserver(this);
spriteAtlas.resize(pixelRatio);
@@ -104,10 +99,18 @@ void ResourceLoader::onGlyphRangeLoaded() {
emitTileDataChanged();
}
+void ResourceLoader::onGlyphRangeLoadingFailed(std::exception_ptr error) {
+ emitResourceLoadingFailed(error);
+}
+
void ResourceLoader::onSourceLoaded() {
emitTileDataChanged();
}
+void ResourceLoader::onSourceLoadingFailed(std::exception_ptr error) {
+ emitResourceLoadingFailed(error);
+}
+
void ResourceLoader::onTileLoaded(bool isNewTile) {
if (isNewTile) {
shouldReparsePartialTiles_ = true;
@@ -116,12 +119,20 @@ void ResourceLoader::onTileLoaded(bool isNewTile) {
emitTileDataChanged();
}
+void ResourceLoader::onTileLoadingFailed(std::exception_ptr error) {
+ emitResourceLoadingFailed(error);
+}
+
void ResourceLoader::onSpriteLoaded() {
shouldReparsePartialTiles_ = true;
emitTileDataChanged();
}
+void ResourceLoader::onSpriteLoadingFailed(std::exception_ptr error) {
+ emitResourceLoadingFailed(error);
+}
+
void ResourceLoader::emitTileDataChanged() {
assert(Environment::currentlyOn(ThreadType::Map));
@@ -130,4 +141,20 @@ void ResourceLoader::emitTileDataChanged() {
}
}
+void ResourceLoader::emitResourceLoadingFailed(std::exception_ptr error) {
+ assert(Environment::currentlyOn(ThreadType::Map));
+
+ try {
+ if (error) {
+ std::rethrow_exception(error);
+ }
+ } catch(const std::exception& e) {
+ Log::Error(Event::ResourceLoader, e.what());
+ }
+
+ if (observer_) {
+ observer_->onResourceLoadingFailed(error);
+ }
+}
+
}
diff --git a/src/mbgl/map/resource_loader.hpp b/src/mbgl/map/resource_loader.hpp
index 379444135e..525e4653a0 100644
--- a/src/mbgl/map/resource_loader.hpp
+++ b/src/mbgl/map/resource_loader.hpp
@@ -32,6 +32,7 @@ public:
virtual ~Observer() = default;
virtual void onTileDataChanged() = 0;
+ virtual void onResourceLoadingFailed(std::exception_ptr error) = 0;
};
ResourceLoader();
@@ -48,9 +49,6 @@ public:
// style.
void setGlyphStore(GlyphStore* glyphStore);
- // Set the access token to be used for loading the tile data.
- void setAccessToken(const std::string& accessToken);
-
// Fetch the tiles needed by the current viewport and emit a signal when
// a tile is ready so observers can render the tile.
void update(MapData&, const TransformState&, GlyphAtlas&, SpriteAtlas&, TexturePool&);
@@ -62,20 +60,24 @@ public:
// GlyphStore::Observer implementation.
void onGlyphRangeLoaded() override;
+ void onGlyphRangeLoadingFailed(std::exception_ptr error) override;
// Source::Observer implementation.
void onSourceLoaded() override;
+ void onSourceLoadingFailed(std::exception_ptr error) override;
void onTileLoaded(bool isNewTile) override;
+ void onTileLoadingFailed(std::exception_ptr error) override;
// Sprite::Observer implementation.
void onSpriteLoaded() override;
+ void onSpriteLoadingFailed(std::exception_ptr error) override;
private:
void emitTileDataChanged();
+ void emitResourceLoadingFailed(std::exception_ptr error);
bool shouldReparsePartialTiles_ = false;
- std::string accessToken_;
util::ptr<Sprite> sprite_;
GlyphStore* glyphStore_ = nullptr;
diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp
index 331e48436f..b6838a4713 100644
--- a/src/mbgl/map/source.cpp
+++ b/src/mbgl/map/source.cpp
@@ -4,6 +4,7 @@
#include <mbgl/map/transform.hpp>
#include <mbgl/map/tile.hpp>
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/util/exception.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
@@ -13,6 +14,7 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/uv_detail.hpp>
+#include <mbgl/util/std.hpp>
#include <mbgl/util/token.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/tile_cover.hpp>
@@ -139,18 +141,19 @@ bool Source::isLoaded() const {
// Note: This is a separate function that must be called exactly once after creation
// The reason this isn't part of the constructor is that calling shared_from_this() in
// the constructor fails.
-void Source::load(const std::string& accessToken) {
+void Source::load() {
if (info.url.empty()) {
loaded = true;
return;
}
- const std::string url = util::mapbox::normalizeSourceURL(info.url, accessToken);
- req = Environment::Get().request({ Resource::Kind::JSON, url }, [this](const Response &res) {
+ req = Environment::Get().request({ Resource::Kind::Source, info.url }, [this](const Response &res) {
req = nullptr;
if (res.status != Response::Successful) {
- Log::Warning(Event::General, "Failed to load source TileJSON: %s", res.message.c_str());
+ std::stringstream message;
+ message << "Failed to load [" << info.url << "]: " << res.message;
+ emitSourceLoadingFailed(message.str());
return;
}
@@ -158,7 +161,9 @@ void Source::load(const std::string& accessToken) {
d.Parse<0>(res.data.c_str());
if (d.HasParseError()) {
- Log::Error(Event::General, "Invalid source TileJSON; Parse Error at %d: %s", d.GetErrorOffset(), d.GetParseError());
+ std::stringstream message;
+ message << "Failed to parse [" << info.url << "]: " << d.GetErrorOffset() << " - " << d.GetParseError();
+ emitSourceLoadingFailed(message.str());
return;
}
@@ -261,7 +266,8 @@ TileData::State Source::addTile(MapData& data,
}
const float overscaling = id.z > info.max_zoom ? std::pow(2.0f, id.z - info.max_zoom) : 1.0f;
- auto pos = tiles.emplace(id, util::make_unique<Tile>(id));//, util::tileSize * overscaling));
+ auto pos = tiles.emplace(id, std::make_unique<Tile>(id));
+
Tile& new_tile = *pos.first->second;
// We couldn't find the tile in the list. Create a new one.
@@ -283,8 +289,9 @@ TileData::State Source::addTile(MapData& data,
new_tile.data = cache.get(normalized_id.to_uint64());
}
- auto callback = std::bind(&Source::emitTileLoaded, this, true);
if (!new_tile.data) {
+ auto callback = std::bind(&Source::tileLoadingCompleteCallback, this, normalized_id);
+
// If we don't find working tile data, we're just going to load it.
if (info.type == SourceType::Vector) {
new_tile.data =
@@ -294,7 +301,8 @@ TileData::State Source::addTile(MapData& data,
new_tile.data->request(style.workers, transformState.getPixelRatio(), callback);
} else if (info.type == SourceType::Raster) {
new_tile.data = std::make_shared<RasterTileData>(normalized_id, texturePool, info);
- new_tile.data->request(style.workers, transformState.getPixelRatio(), callback);
+ new_tile.data->request(
+ style.workers, transformState.getPixelRatio(), callback);
} else if (info.type == SourceType::Annotations) {
new_tile.data = std::make_shared<LiveTileData>(normalized_id, data.annotationManager,
style, glyphAtlas,
@@ -546,16 +554,53 @@ void Source::setObserver(Observer* observer) {
observer_ = observer;
}
+void Source::tileLoadingCompleteCallback(const TileID& normalized_id) {
+ auto it = tile_data.find(normalized_id);
+ if (it == tile_data.end()) {
+ return;
+ }
+
+ util::ptr<TileData> data = it->second.lock();
+ if (!data) {
+ return;
+ }
+
+ if (data->getState() == TileData::State::obsolete && !data->getError().empty()) {
+ emitTileLoadingFailed(data->getError());
+ return;
+ }
+
+ emitTileLoaded(true);
+}
+
void Source::emitSourceLoaded() {
if (observer_) {
observer_->onSourceLoaded();
}
}
+void Source::emitSourceLoadingFailed(const std::string& message) {
+ if (!observer_) {
+ return;
+ }
+
+ auto error = std::make_exception_ptr(util::SourceLoadingException(message));
+ observer_->onSourceLoadingFailed(error);
+}
+
void Source::emitTileLoaded(bool isNewTile) {
if (observer_) {
observer_->onTileLoaded(isNewTile);
}
}
+void Source::emitTileLoadingFailed(const std::string& message) {
+ if (!observer_) {
+ return;
+ }
+
+ auto error = std::make_exception_ptr(util::TileLoadingException(message));
+ observer_->onTileLoadingFailed(error);
+}
+
}
diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp
index 505292cc74..bf49bd69ea 100644
--- a/src/mbgl/map/source.hpp
+++ b/src/mbgl/map/source.hpp
@@ -58,13 +58,16 @@ public:
virtual ~Observer() = default;
virtual void onSourceLoaded() = 0;
+ virtual void onSourceLoadingFailed(std::exception_ptr error) = 0;
+
virtual void onTileLoaded(bool isNewTile) = 0;
+ virtual void onTileLoadingFailed(std::exception_ptr error) = 0;
};
Source();
~Source();
- void load(const std::string& accessToken);
+ void load();
bool isLoaded() const;
void load(MapData&, Environment&, std::function<void()> callback);
@@ -102,8 +105,12 @@ public:
private:
void redoPlacement(const TransformState& transformState, bool collisionDebug);
+ void tileLoadingCompleteCallback(const TileID& normalized_id);
+
void emitSourceLoaded();
+ void emitSourceLoadingFailed(const std::string& message);
void emitTileLoaded(bool isNewTile);
+ void emitTileLoadingFailed(const std::string& message);
bool handlePartialTile(const TileID &id, Worker &worker);
bool findLoadedChildren(const TileID& id, int32_t maxCoveringZoom, std::forward_list<TileID>& retain);
diff --git a/src/mbgl/map/sprite.cpp b/src/mbgl/map/sprite.cpp
index cfc0974571..d5af3e1d1d 100644
--- a/src/mbgl/map/sprite.cpp
+++ b/src/mbgl/map/sprite.cpp
@@ -1,17 +1,19 @@
#include <mbgl/map/sprite.hpp>
-#include <mbgl/util/raster.hpp>
-#include <mbgl/platform/log.hpp>
-#include <string>
-#include <mbgl/platform/platform.hpp>
#include <mbgl/map/environment.hpp>
+#include <mbgl/platform/log.hpp>
+#include <mbgl/platform/platform.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
+#include <mbgl/util/exception.hpp>
+#include <mbgl/util/raster.hpp>
#include <mbgl/util/uv_detail.hpp>
-#include <mbgl/util/std.hpp>
#include <rapidjson/document.h>
+#include <string>
+#include <sstream>
+
using namespace mbgl;
SpritePosition::SpritePosition(uint16_t x_, uint16_t y_, uint16_t width_, uint16_t height_, float pixelRatio_, bool sdf_)
@@ -39,27 +41,31 @@ Sprite::Sprite(const std::string& baseUrl, float pixelRatio_)
std::string spriteURL(baseUrl + (pixelRatio_ > 1 ? "@2x" : "") + ".png");
std::string jsonURL(baseUrl + (pixelRatio_ > 1 ? "@2x" : "") + ".json");
- jsonRequest = env.request({ Resource::Kind::JSON, jsonURL }, [this](const Response &res) {
+ jsonRequest = env.request({ Resource::Kind::JSON, jsonURL }, [this, jsonURL](const Response &res) {
jsonRequest = nullptr;
if (res.status == Response::Successful) {
body = res.data;
- parseJSON();
+ parseJSON(jsonURL);
} else {
- Log::Warning(Event::Sprite, "Failed to load sprite info: %s", res.message.c_str());
+ std::stringstream message;
+ message << "Failed to load [" << jsonURL << "]: " << res.message;
+ emitSpriteLoadingFailed(message.str());
+ return;
}
- loadedJSON = true;
emitSpriteLoadedIfComplete();
});
- spriteRequest = env.request({ Resource::Kind::Image, spriteURL }, [this](const Response &res) {
+ spriteRequest = env.request({ Resource::Kind::Image, spriteURL }, [this, spriteURL](const Response &res) {
spriteRequest = nullptr;
if (res.status == Response::Successful) {
image = res.data;
- parseImage();
+ parseImage(spriteURL);
} else {
- Log::Warning(Event::Sprite, "Failed to load sprite image: %s", res.message.c_str());
+ std::stringstream message;
+ message << "Failed to load [" << spriteURL << "]: " << res.message;
+ emitSpriteLoadingFailed(message.str());
+ return;
}
- loadedImage = true;
emitSpriteLoadedIfComplete();
});
}
@@ -80,6 +86,15 @@ void Sprite::emitSpriteLoadedIfComplete() {
}
}
+void Sprite::emitSpriteLoadingFailed(const std::string& message) {
+ if (!observer) {
+ return;
+ }
+
+ auto error = std::make_exception_ptr(util::SpriteLoadingException(message));
+ observer->onSpriteLoadingFailed(error);
+}
+
bool Sprite::isLoaded() const {
return loadedImage && loadedJSON;
}
@@ -88,21 +103,29 @@ bool Sprite::hasPixelRatio(float ratio) const {
return pixelRatio == (ratio > 1 ? 2 : 1);
}
-void Sprite::parseImage() {
- raster = util::make_unique<util::Image>(image);
+void Sprite::parseImage(const std::string& spriteURL) {
+ raster = std::make_unique<util::Image>(image);
if (!*raster) {
raster.reset();
+ std::stringstream message;
+ message << "Failed to parse [" << spriteURL << "]";
+ emitSpriteLoadingFailed(message.str());
+ return;
}
+
image.clear();
+ loadedImage = true;
}
-void Sprite::parseJSON() {
+void Sprite::parseJSON(const std::string& jsonURL) {
rapidjson::Document d;
d.Parse<0>(body.c_str());
body.clear();
if (d.HasParseError()) {
- Log::Warning(Event::Sprite, "sprite JSON is invalid");
+ std::stringstream message;
+ message << "Failed to parse [" << jsonURL << "]: " << d.GetErrorOffset() << " - " << d.GetParseError();
+ emitSpriteLoadingFailed(message.str());
} else if (d.IsObject()) {
for (rapidjson::Value::ConstMemberIterator itr = d.MemberBegin(); itr != d.MemberEnd(); ++itr) {
const std::string& name = itr->name.GetString();
@@ -125,8 +148,11 @@ void Sprite::parseJSON() {
pos.emplace(name, SpritePosition { x, y, width, height, spritePixelRatio, sdf });
}
}
+ loadedJSON = true;
} else {
- Log::Warning(Event::Sprite, "sprite JSON root is not an object");
+ std::stringstream message;
+ message << "Failed to parse [" << jsonURL << "]: Root is not an object";
+ emitSpriteLoadingFailed(message.str());
}
}
diff --git a/src/mbgl/map/sprite.hpp b/src/mbgl/map/sprite.hpp
index ccf2561618..b0fda30018 100644
--- a/src/mbgl/map/sprite.hpp
+++ b/src/mbgl/map/sprite.hpp
@@ -39,6 +39,7 @@ public:
virtual ~Observer() = default;
virtual void onSpriteLoaded() = 0;
+ virtual void onSpriteLoadingFailed(std::exception_ptr error) = 0;
};
Sprite(const std::string& baseUrl, float pixelRatio);
@@ -56,9 +57,10 @@ public:
void setObserver(Observer* observer);
private:
void emitSpriteLoadedIfComplete();
+ void emitSpriteLoadingFailed(const std::string& message);
- void parseJSON();
- void parseImage();
+ void parseJSON(const std::string& jsonURL);
+ void parseImage(const std::string& spriteURL);
std::string body;
std::string image;
diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp
index 83488ecb9b..6ff92bb6e5 100644
--- a/src/mbgl/map/tile_data.cpp
+++ b/src/mbgl/map/tile_data.cpp
@@ -1,12 +1,14 @@
#include <mbgl/map/tile_data.hpp>
+
#include <mbgl/map/environment.hpp>
#include <mbgl/map/source.hpp>
#include <mbgl/map/transform_state.hpp>
-
+#include <mbgl/platform/log.hpp>
#include <mbgl/storage/file_source.hpp>
-#include <mbgl/util/worker.hpp>
#include <mbgl/util/work_request.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/worker.hpp>
+
+#include <sstream>
using namespace mbgl;
@@ -35,7 +37,9 @@ void TileData::setState(const State& state_) {
state = state_;
}
-void TileData::request(Worker& worker, float pixelRatio, std::function<void()> callback) {
+void TileData::request(Worker& worker,
+ float pixelRatio,
+ const std::function<void()>& callback) {
std::string url = source.tileURL(id, pixelRatio);
state = State::loading;
@@ -43,7 +47,10 @@ void TileData::request(Worker& worker, float pixelRatio, std::function<void()> c
req = nullptr;
if (res.status != Response::Successful) {
- Log::Error(Event::HttpRequest, "[%s] tile loading failed: %s", url.c_str(), res.message.c_str());
+ std::stringstream message;
+ message << "Failed to load [" << url << "]: " << res.message;
+ setError(message.str());
+ callback();
return;
}
@@ -82,3 +89,8 @@ bool TileData::reparse(Worker& worker, std::function<void()> callback) {
workRequest = worker.send([this] { parse(); endParsing(); }, callback);
return true;
}
+
+void TileData::setError(const std::string& message) {
+ error = message;
+ setState(State::obsolete);
+}
diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp
index 1ec58ec839..2b237a61cb 100644
--- a/src/mbgl/map/tile_data.hpp
+++ b/src/mbgl/map/tile_data.hpp
@@ -45,7 +45,7 @@ public:
TileData(const TileID&, const SourceInfo&);
~TileData();
- void request(Worker&, float pixelRatio, std::function<void ()> callback);
+ void request(Worker&, float pixelRatio, const std::function<void()>& callback);
// Schedule a tile reparse on a worker thread and call the callback on
// completion. It will return true if the work was schedule or false it was
@@ -69,13 +69,20 @@ public:
// We let subclasses override setState() so they
// can intercept the state change and react accordingly.
virtual void setState(const State& state);
-
inline State getState() const {
return state;
}
void endParsing();
+ // Error message to be set in case of request
+ // and parsing errors.
+ void setError(const std::string& message);
+
+ std::string getError() const {
+ return error;
+ }
+
// Override this in the child class.
virtual void parse() = 0;
virtual Bucket* getBucket(StyleLayer const &layer_desc) = 0;
@@ -106,6 +113,8 @@ protected:
private:
std::atomic<State> state;
+ std::string error;
+
protected:
// Contains the tile ID string for painting debug information.
DebugFontBuffer debugFontBuffer;
diff --git a/src/mbgl/map/tile_parser.cpp b/src/mbgl/map/tile_parser.cpp
index eb9a7c2e9f..61af227034 100644
--- a/src/mbgl/map/tile_parser.cpp
+++ b/src/mbgl/map/tile_parser.cpp
@@ -8,7 +8,6 @@
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/util/constants.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/style/style.hpp>
#include <locale>
@@ -154,7 +153,7 @@ void TileParser::addBucketGeometries(Bucket& bucket, const GeometryTileLayer& la
std::unique_ptr<Bucket> TileParser::createFillBucket(const GeometryTileLayer& layer,
const StyleBucket& bucket_desc) {
- auto bucket = util::make_unique<FillBucket>(tile.fillVertexBuffer,
+ auto bucket = std::make_unique<FillBucket>(tile.fillVertexBuffer,
tile.triangleElementsBuffer,
tile.lineElementsBuffer);
addBucketGeometries(bucket, layer, bucket_desc.filter);
@@ -163,7 +162,7 @@ std::unique_ptr<Bucket> TileParser::createFillBucket(const GeometryTileLayer& la
std::unique_ptr<Bucket> TileParser::createLineBucket(const GeometryTileLayer& layer,
const StyleBucket& bucket_desc) {
- auto bucket = util::make_unique<LineBucket>(tile.lineVertexBuffer,
+ auto bucket = std::make_unique<LineBucket>(tile.lineVertexBuffer,
tile.triangleElementsBuffer);
const float z = tile.id.z;
@@ -180,7 +179,7 @@ std::unique_ptr<Bucket> TileParser::createLineBucket(const GeometryTileLayer& la
std::unique_ptr<Bucket> TileParser::createSymbolBucket(const GeometryTileLayer& layer,
const StyleBucket& bucket_desc) {
- auto bucket = util::make_unique<SymbolBucket>(*tile.getCollision(), tile.id.overscaling);
+ auto bucket = std::make_unique<SymbolBucket>(*tile.getCollision(), tile.id.overscaling);
const float z = tile.id.z;
auto& layout = bucket->layout;
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 32127fb26f..182e534295 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -2,7 +2,6 @@
#include <mbgl/map/view.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/mat4.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/unitbezier.hpp>
#include <mbgl/util/interpolate.hpp>
@@ -384,6 +383,7 @@ void Transform::_setAngle(double new_angle, const Duration duration) {
MapChangeRegionWillChange);
final.angle = _normalizeAngle(new_angle, current.angle);
+ current.angle = _normalizeAngle(current.angle, final.angle);
if (duration == Duration::zero()) {
current.angle = final.angle;
diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp
index fb64c224cf..4cb657038d 100644
--- a/src/mbgl/map/vector_tile_data.cpp
+++ b/src/mbgl/map/vector_tile_data.cpp
@@ -1,6 +1,5 @@
#include <mbgl/map/vector_tile_data.hpp>
#include <mbgl/map/tile_parser.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/map/source.hpp>
@@ -31,7 +30,7 @@ VectorTileData::VectorTileData(const TileID& id_,
sprite(sprite_),
style(style_),
overscaling(overscaling_),
- collision(util::make_unique<CollisionTile>(id_.z, 4096, source_.tile_size * id.overscaling, angle, collisionDebug)),
+ collision(std::make_unique<CollisionTile>(id_.z, 4096, source_.tile_size * id.overscaling, angle, collisionDebug)),
lastAngle(angle),
currentAngle(angle) {
}
@@ -68,9 +67,9 @@ void VectorTileData::parse() {
redoPlacement();
}
} catch (const std::exception& ex) {
- Log::Error(Event::ParseTile, "Parsing [%d/%d/%d] failed: %s", id.z, id.x, id.y, ex.what());
- setState(State::obsolete);
- return;
+ std::stringstream message;
+ message << "Failed to parse [" << int(id.z) << "/" << id.x << "/" << id.y << "]: " << ex.what();
+ setError(message.str());
}
}
diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp
index c59b0970e0..a98a8b7cdf 100644
--- a/src/mbgl/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/fill_bucket.cpp
@@ -7,7 +7,6 @@
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/shader/pattern_shader.hpp>
#include <mbgl/shader/outline_shader.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/platform/gl.hpp>
#include <mbgl/platform/log.hpp>
@@ -107,7 +106,7 @@ void FillBucket::tessellate() {
if (!lineGroups.size() || (lineGroups.back()->vertex_length + total_vertex_count > 65535)) {
// Move to a new group because the old one can't hold the geometry.
- lineGroups.emplace_back(util::make_unique<LineGroup>());
+ lineGroups.emplace_back(std::make_unique<LineGroup>());
}
assert(lineGroups.back());
@@ -154,7 +153,7 @@ void FillBucket::tessellate() {
if (!triangleGroups.size() || (triangleGroups.back()->vertex_length + total_vertex_count > 65535)) {
// Move to a new group because the old one can't hold the geometry.
- triangleGroups.emplace_back(util::make_unique<TriangleGroup>());
+ triangleGroups.emplace_back(std::make_unique<TriangleGroup>());
}
// We're generating triangle fans, so we always start with the first
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index bbfc02ead1..f696874afe 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
@@ -8,7 +8,6 @@
#include <mbgl/shader/linesdf_shader.hpp>
#include <mbgl/shader/linepattern_shader.hpp>
#include <mbgl/util/math.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/platform/gl.hpp>
#ifndef BUFFER_OFFSET
@@ -290,7 +289,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
if (!triangleGroups.size() ||
(triangleGroups.back()->vertex_length + vertexCount > 65535)) {
// Move to a new group because the old one can't hold the geometry.
- triangleGroups.emplace_back(util::make_unique<TriangleGroup>());
+ triangleGroups.emplace_back(std::make_unique<TriangleGroup>());
}
assert(triangleGroups.back());
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index 722a520027..977b6e565f 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -27,7 +27,6 @@
#include <mbgl/shader/gaussian_shader.hpp>
#include <mbgl/shader/box_shader.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/mat3.hpp>
@@ -95,19 +94,19 @@ void Painter::setup() {
}
void Painter::setupShaders() {
- if (!plainShader) plainShader = util::make_unique<PlainShader>();
- if (!outlineShader) outlineShader = util::make_unique<OutlineShader>();
- if (!lineShader) lineShader = util::make_unique<LineShader>();
- if (!linesdfShader) linesdfShader = util::make_unique<LineSDFShader>();
- if (!linepatternShader) linepatternShader = util::make_unique<LinepatternShader>();
- if (!patternShader) patternShader = util::make_unique<PatternShader>();
- if (!iconShader) iconShader = util::make_unique<IconShader>();
- if (!rasterShader) rasterShader = util::make_unique<RasterShader>();
- if (!sdfGlyphShader) sdfGlyphShader = util::make_unique<SDFGlyphShader>();
- if (!sdfIconShader) sdfIconShader = util::make_unique<SDFIconShader>();
- if (!dotShader) dotShader = util::make_unique<DotShader>();
- if (!gaussianShader) gaussianShader = util::make_unique<GaussianShader>();
- if (!collisionBoxShader) collisionBoxShader = util::make_unique<CollisionBoxShader>();
+ if (!plainShader) plainShader = std::make_unique<PlainShader>();
+ if (!outlineShader) outlineShader = std::make_unique<OutlineShader>();
+ if (!lineShader) lineShader = std::make_unique<LineShader>();
+ if (!linesdfShader) linesdfShader = std::make_unique<LineSDFShader>();
+ if (!linepatternShader) linepatternShader = std::make_unique<LinepatternShader>();
+ if (!patternShader) patternShader = std::make_unique<PatternShader>();
+ if (!iconShader) iconShader = std::make_unique<IconShader>();
+ if (!rasterShader) rasterShader = std::make_unique<RasterShader>();
+ if (!sdfGlyphShader) sdfGlyphShader = std::make_unique<SDFGlyphShader>();
+ if (!sdfIconShader) sdfIconShader = std::make_unique<SDFIconShader>();
+ if (!dotShader) dotShader = std::make_unique<DotShader>();
+ if (!gaussianShader) gaussianShader = std::make_unique<GaussianShader>();
+ if (!collisionBoxShader) collisionBoxShader = std::make_unique<CollisionBoxShader>();
}
void Painter::resize() {
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index 649bd46794..b2fdafadbd 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
@@ -9,7 +9,6 @@
#include <mbgl/shader/outline_shader.hpp>
#include <mbgl/shader/pattern_shader.hpp>
#include <mbgl/shader/plain_shader.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/mat3.hpp>
using namespace mbgl;
diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp
index 61aff9c1a8..2a8f8e7078 100644
--- a/src/mbgl/renderer/painter_raster.cpp
+++ b/src/mbgl/renderer/painter_raster.cpp
@@ -3,7 +3,6 @@
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/shader/raster_shader.hpp>
-#include <mbgl/util/std.hpp>
using namespace mbgl;
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index 359a9fe9f8..b0b8a6db4f 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
@@ -9,6 +9,7 @@
#include <mbgl/text/get_anchors.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/text/font_stack.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/shader/sdf_shader.hpp>
@@ -217,7 +218,7 @@ void SymbolBucket::addFeatures(uintptr_t tileUID,
layout.text.justify == TextJustifyType::Left ? 0 :
0.5;
- auto* fontStack = glyphStore.getFontStack(layout.text.font);
+ auto fontStack = glyphStore.getFontStack(layout.text.font);
for (const auto& feature : features) {
if (!feature.geometry.size()) continue;
@@ -241,7 +242,7 @@ void SymbolBucket::addFeatures(uintptr_t tileUID,
// Add the glyphs we need for this label to the glyph atlas.
if (shapedText) {
- glyphAtlas.addGlyphs(tileUID, feature.label, layout.text.font, *fontStack, face);
+ glyphAtlas.addGlyphs(tileUID, feature.label, layout.text.font, **fontStack, face);
}
}
@@ -322,7 +323,7 @@ void SymbolBucket::placeFeatures() {
void SymbolBucket::placeFeatures(bool swapImmediately) {
- renderDataInProgress = util::make_unique<SymbolRenderData>();
+ renderDataInProgress = std::make_unique<SymbolRenderData>();
// Calculate which labels can be shown and when they can be shown and
// create the bufers used for rendering.
@@ -427,7 +428,7 @@ void SymbolBucket::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float
if (!buffer.groups.size() ||
(buffer.groups.back()->vertex_length + glyph_vertex_length > 65535)) {
// Move to a new group because the old one can't hold the geometry.
- buffer.groups.emplace_back(util::make_unique<GroupType>());
+ buffer.groups.emplace_back(std::make_unique<GroupType>());
}
// We're generating triangle fans, so we always start with the first
@@ -488,7 +489,7 @@ void SymbolBucket::addToDebugBuffers() {
auto& collisionBox = renderDataInProgress->collisionBox;
if (!collisionBox.groups.size()) {
// Move to a new group because the old one can't hold the geometry.
- collisionBox.groups.emplace_back(util::make_unique<CollisionBoxElementGroup>());
+ collisionBox.groups.emplace_back(std::make_unique<CollisionBoxElementGroup>());
}
collisionBox.vertices.add(anchor.x, anchor.y, tl.x, tl.y, maxZoom, placementZoom);
diff --git a/src/mbgl/shader/shader.cpp b/src/mbgl/shader/shader.cpp
index a079409aa0..6210c1c32e 100644
--- a/src/mbgl/shader/shader.cpp
+++ b/src/mbgl/shader/shader.cpp
@@ -51,7 +51,7 @@ Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSo
if (status == 0) {
GLint logLength;
MBGL_CHECK_ERROR(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength));
- std::unique_ptr<GLchar[]> log = mbgl::util::make_unique<GLchar[]>(logLength);
+ const auto log = std::make_unique<GLchar[]>(logLength);
if (logLength > 0) {
MBGL_CHECK_ERROR(glGetProgramInfoLog(program, logLength, &logLength, log.get()));
Log::Error(Event::Shader, "Program failed to link: %s", log.get());
@@ -76,7 +76,7 @@ Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSo
if (status == 0) {
GLint logLength;
MBGL_CHECK_ERROR(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength));
- std::unique_ptr<GLchar[]> log = mbgl::util::make_unique<GLchar[]>(logLength);
+ const auto log = std::make_unique<GLchar[]>(logLength);
if (logLength > 0) {
MBGL_CHECK_ERROR(glGetProgramInfoLog(program, logLength, &logLength, log.get()));
Log::Error(Event::Shader, "Program failed to validate: %s", log.get());
@@ -115,7 +115,7 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
GLint logLength;
MBGL_CHECK_ERROR(glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength));
if (logLength > 0) {
- std::unique_ptr<GLchar[]> log = mbgl::util::make_unique<GLchar[]>(logLength);
+ const auto log = std::make_unique<GLchar[]>(logLength);
MBGL_CHECK_ERROR(glGetShaderInfoLog(*shader, logLength, &logLength, log.get()));
Log::Error(Event::Shader, "Shader failed to compile: %s", log.get());
}
diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp
index e8831f5465..b46696aaa3 100644
--- a/src/mbgl/storage/default_file_source.cpp
+++ b/src/mbgl/storage/default_file_source.cpp
@@ -5,11 +5,12 @@
#include <mbgl/storage/response.hpp>
#include <mbgl/platform/platform.hpp>
+#include <mbgl/platform/log.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/thread.hpp>
-#include <mbgl/platform/log.hpp>
+#include <mbgl/util/mapbox.hpp>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
@@ -27,7 +28,7 @@ namespace algo = boost::algorithm;
namespace mbgl {
DefaultFileSource::DefaultFileSource(FileCache* cache, const std::string& root)
- : thread(util::make_unique<util::Thread<Impl>>("FileSource", util::ThreadPriority::Low, cache, root)) {
+ : thread(std::make_unique<util::Thread<Impl>>("FileSource", util::ThreadPriority::Low, cache, root)) {
}
DefaultFileSource::~DefaultFileSource() {
@@ -38,7 +39,27 @@ Request* DefaultFileSource::request(const Resource& resource,
uv_loop_t* l,
Callback callback) {
assert(l);
- auto req = new Request(resource, l, std::move(callback));
+
+ std::string url;
+
+ switch (resource.kind) {
+ case Resource::Kind::Style:
+ url = mbgl::util::mapbox::normalizeStyleURL(resource.url, accessToken);
+ break;
+
+ case Resource::Kind::Source:
+ url = util::mapbox::normalizeSourceURL(resource.url, accessToken);
+ break;
+
+ case Resource::Kind::Glyphs:
+ url = util::mapbox::normalizeGlyphsURL(resource.url, accessToken);
+ break;
+
+ default:
+ url = resource.url;
+ }
+
+ auto req = new Request({ resource.kind, url }, l, std::move(callback));
thread->invoke(&Impl::add, req);
return req;
}
diff --git a/src/mbgl/storage/request.cpp b/src/mbgl/storage/request.cpp
index a6d845ce4a..b653a41e71 100644
--- a/src/mbgl/storage/request.cpp
+++ b/src/mbgl/storage/request.cpp
@@ -4,7 +4,6 @@
#include <mbgl/storage/response.hpp>
#include <mbgl/util/util.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <cassert>
@@ -16,7 +15,7 @@ struct Request::Canceled { std::mutex mutex; bool confirmed = false; };
// Note: This requires that loop is running in the current thread (or not yet running).
Request::Request(const Resource &resource_, uv_loop_t *loop, Callback callback_)
- : async(util::make_unique<uv::async>(loop, [this] { notifyCallback(); })),
+ : async(std::make_unique<uv::async>(loop, [this] { notifyCallback(); })),
callback(callback_),
resource(resource_) {
}
@@ -62,7 +61,7 @@ void Request::notify(const std::shared_ptr<const Response> &response_) {
void Request::cancel() {
assert(async);
assert(!canceled);
- canceled = util::make_unique<Canceled>();
+ canceled = std::make_unique<Canceled>();
}
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index 51d92fdcaf..0acf66eb56 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -5,7 +5,6 @@
#include <mbgl/style/style_parser.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/util/constants.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/platform/log.hpp>
#include <csscolorparser/csscolorparser.hpp>
@@ -17,7 +16,7 @@
namespace mbgl {
Style::Style()
- : mtx(util::make_unique<uv::rwlock>()),
+ : mtx(std::make_unique<uv::rwlock>()),
workers(4) {
}
diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp
index 313fe3df89..83a113f885 100644
--- a/src/mbgl/style/style_parser.cpp
+++ b/src/mbgl/style/style_parser.cpp
@@ -3,7 +3,6 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/map/annotation.hpp>
#include <mbgl/util/constants.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/vec.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/platform/log.hpp>
diff --git a/src/mbgl/text/font_stack.cpp b/src/mbgl/text/font_stack.cpp
new file mode 100644
index 0000000000..adabe2eb69
--- /dev/null
+++ b/src/mbgl/text/font_stack.cpp
@@ -0,0 +1,140 @@
+#include <mbgl/text/font_stack.hpp>
+#include <cassert>
+#include <mbgl/util/math.hpp>
+
+namespace mbgl {
+
+void FontStack::insert(uint32_t id, const SDFGlyph &glyph) {
+ metrics.emplace(id, glyph.metrics);
+ bitmaps.emplace(id, glyph.bitmap);
+ sdfs.emplace(id, glyph);
+}
+
+const std::map<uint32_t, GlyphMetrics> &FontStack::getMetrics() const {
+ return metrics;
+}
+
+const std::map<uint32_t, SDFGlyph> &FontStack::getSDFs() const {
+ return sdfs;
+}
+
+const Shaping FontStack::getShaping(const std::u32string &string, const float maxWidth,
+ const float lineHeight, const float horizontalAlign,
+ const float verticalAlign, const float justify,
+ const float spacing, const vec2<float> &translate) const {
+ Shaping shaping(translate.x * 24, translate.y * 24);
+
+ // the y offset *should* be part of the font metadata
+ const int32_t yOffset = -17;
+
+ int32_t x = std::round(translate.x * 24); // one em
+ const int32_t y = std::round(translate.y * 24) + yOffset; // one em
+
+ // Loop through all characters of this label and shape.
+ for (uint32_t chr : string) {
+ shaping.positionedGlyphs.emplace_back(chr, x, y);
+ auto metric = metrics.find(chr);
+ if (metric != metrics.end()) {
+ x += metric->second.advance + spacing;
+ }
+ }
+
+ if (!shaping.positionedGlyphs.size())
+ return shaping;
+
+ lineWrap(shaping, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify);
+
+ return shaping;
+}
+
+void align(Shaping &shaping, const float justify, const float horizontalAlign,
+ const float verticalAlign, const uint32_t maxLineLength, const float lineHeight,
+ const uint32_t line) {
+ const float shiftX = (justify - horizontalAlign) * maxLineLength;
+ const float shiftY = (-verticalAlign * (line + 1) + 0.5) * lineHeight;
+
+ for (auto& glyph : shaping.positionedGlyphs) {
+ glyph.x += shiftX;
+ glyph.y += shiftY;
+ }
+}
+
+void justifyLine(std::vector<PositionedGlyph> &positionedGlyphs, const std::map<uint32_t, GlyphMetrics> &metrics, uint32_t start,
+ uint32_t end, float justify) {
+ PositionedGlyph &glyph = positionedGlyphs[end];
+ auto metric = metrics.find(glyph.glyph);
+ if (metric != metrics.end()) {
+ const uint32_t lastAdvance = metric->second.advance;
+ const float lineIndent = float(glyph.x + lastAdvance) * justify;
+
+ for (uint32_t j = start; j <= end; j++) {
+ positionedGlyphs[j].x -= lineIndent;
+ }
+ }
+}
+
+void FontStack::lineWrap(Shaping &shaping, const float lineHeight, const float maxWidth,
+ const float horizontalAlign, const float verticalAlign,
+ const float justify) const {
+ uint32_t lastSafeBreak = 0;
+
+ uint32_t lengthBeforeCurrentLine = 0;
+ uint32_t lineStartIndex = 0;
+ uint32_t line = 0;
+
+ uint32_t maxLineLength = 0;
+
+ std::vector<PositionedGlyph> &positionedGlyphs = shaping.positionedGlyphs;
+
+ if (maxWidth) {
+ for (uint32_t i = 0; i < positionedGlyphs.size(); i++) {
+ PositionedGlyph &shape = positionedGlyphs[i];
+
+ shape.x -= lengthBeforeCurrentLine;
+ shape.y += lineHeight * line;
+
+ if (shape.x > maxWidth && lastSafeBreak > 0) {
+
+ uint32_t lineLength = positionedGlyphs[lastSafeBreak + 1].x;
+ maxLineLength = util::max(lineLength, maxLineLength);
+
+ for (uint32_t k = lastSafeBreak + 1; k <= i; k++) {
+ positionedGlyphs[k].y += lineHeight;
+ positionedGlyphs[k].x -= lineLength;
+ }
+
+ if (justify) {
+ justifyLine(positionedGlyphs, metrics, lineStartIndex, lastSafeBreak - 1, justify);
+ }
+
+ lineStartIndex = lastSafeBreak + 1;
+ lastSafeBreak = 0;
+ lengthBeforeCurrentLine += lineLength;
+ line++;
+ }
+
+ if (shape.glyph == 32) {
+ lastSafeBreak = i;
+ }
+ }
+ }
+
+ const PositionedGlyph& lastPositionedGlyph = positionedGlyphs.back();
+ const auto lastGlyphMetric = metrics.find(lastPositionedGlyph.glyph);
+ assert(lastGlyphMetric != metrics.end());
+ const uint32_t lastLineLength = lastPositionedGlyph.x + lastGlyphMetric->second.advance;
+ maxLineLength = std::max(maxLineLength, lastLineLength);
+
+ const uint32_t height = (line + 1) * lineHeight;
+
+ justifyLine(positionedGlyphs, metrics, lineStartIndex, uint32_t(positionedGlyphs.size()) - 1, justify);
+ align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line);
+
+ // Calculate the bounding box
+ shaping.top += -verticalAlign * height;
+ shaping.bottom = shaping.top + height;
+ shaping.left += -horizontalAlign * maxLineLength;
+ shaping.right = shaping.left + maxLineLength;
+}
+
+} // end namespace mbgl
diff --git a/src/mbgl/text/font_stack.hpp b/src/mbgl/text/font_stack.hpp
new file mode 100644
index 0000000000..7340cb17a9
--- /dev/null
+++ b/src/mbgl/text/font_stack.hpp
@@ -0,0 +1,28 @@
+#ifndef MBGL_TEXT_FONT_STACK
+#define MBGL_TEXT_FONT_STACK
+
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/util/vec.hpp>
+
+namespace mbgl {
+
+class FontStack {
+public:
+ void insert(uint32_t id, const SDFGlyph &glyph);
+ const std::map<uint32_t, GlyphMetrics> &getMetrics() const;
+ const std::map<uint32_t, SDFGlyph> &getSDFs() const;
+ const Shaping getShaping(const std::u32string &string, float maxWidth, float lineHeight,
+ float horizontalAlign, float verticalAlign, float justify,
+ float spacing, const vec2<float> &translate) const;
+ void lineWrap(Shaping &shaping, float lineHeight, float maxWidth, float horizontalAlign,
+ float verticalAlign, float justify) const;
+
+private:
+ std::map<uint32_t, std::string> bitmaps;
+ std::map<uint32_t, GlyphMetrics> metrics;
+ std::map<uint32_t, SDFGlyph> sdfs;
+};
+
+} // end namespace mbgl
+
+#endif
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
index 03016f0fbf..be7c9befd5 100644
--- a/src/mbgl/text/glyph.hpp
+++ b/src/mbgl/text/glyph.hpp
@@ -5,6 +5,7 @@
#include <cstdint>
#include <vector>
+#include <string>
#include <map>
namespace mbgl {
@@ -68,6 +69,17 @@ class Shaping {
operator bool() const { return positionedGlyphs.size(); }
};
-}
+class SDFGlyph {
+public:
+ uint32_t id = 0;
+
+ // A signed distance field of the glyph with a border of 3 pixels.
+ std::string bitmap;
+
+ // Glyph metrics
+ GlyphMetrics metrics;
+};
+
+} // end namespace mbgl
#endif
diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp
new file mode 100644
index 0000000000..899df39d38
--- /dev/null
+++ b/src/mbgl/text/glyph_pbf.cpp
@@ -0,0 +1,115 @@
+#include <mbgl/text/glyph_pbf.hpp>
+#include <mbgl/text/font_stack.hpp>
+
+#include <mbgl/map/environment.hpp>
+
+#include <mbgl/storage/resource.hpp>
+#include <mbgl/storage/response.hpp>
+
+#include <mbgl/util/pbf.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/token.hpp>
+#include <mbgl/util/url.hpp>
+
+#include <sstream>
+
+namespace mbgl {
+
+GlyphPBF::GlyphPBF(const std::string& glyphURL,
+ const std::string& fontStack,
+ GlyphRange glyphRange,
+ Environment& env_,
+ const GlyphLoadedCallback& successCallback,
+ const GlyphLoadingFailedCallback& failureCallback)
+ : parsed(false), env(env_) {
+ // Load the glyph set URL
+ url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string {
+ if (name == "fontstack") return util::percentEncode(fontStack);
+ if (name == "range") return util::toString(glyphRange.first) + "-" + util::toString(glyphRange.second);
+ return "";
+ });
+
+ // The prepare call jumps back to the main thread.
+ req = env.request({ Resource::Kind::Glyphs, url }, [&, successCallback, failureCallback](const Response &res) {
+ req = nullptr;
+
+ if (res.status != Response::Successful) {
+ std::stringstream message;
+ message << "Failed to load [" << url << "]: " << res.message;
+ failureCallback(message.str());
+ } else {
+ // Transfer the data to the GlyphSet and signal its availability.
+ // Once it is available, the caller will need to call parse() to actually
+ // parse the data we received. We are not doing this here since this callback is being
+ // called from another (unknown) thread.
+ data = res.data;
+ successCallback(this);
+ }
+ });
+}
+
+GlyphPBF::~GlyphPBF() {
+ if (req) {
+ env.cancelRequest(req);
+ }
+}
+
+void GlyphPBF::parse(FontStack &stack) {
+ if (!data.size()) {
+ // If there is no data, this means we either haven't received any data, or
+ // we have already parsed the data.
+ return;
+ }
+
+ // Parse the glyph PBF
+ pbf glyphs_pbf(reinterpret_cast<const uint8_t *>(data.data()), data.size());
+
+ while (glyphs_pbf.next()) {
+ if (glyphs_pbf.tag == 1) { // stacks
+ pbf fontstack_pbf = glyphs_pbf.message();
+ while (fontstack_pbf.next()) {
+ if (fontstack_pbf.tag == 3) { // glyphs
+ pbf glyph_pbf = fontstack_pbf.message();
+
+ SDFGlyph glyph;
+
+ while (glyph_pbf.next()) {
+ if (glyph_pbf.tag == 1) { // id
+ glyph.id = glyph_pbf.varint();
+ } else if (glyph_pbf.tag == 2) { // bitmap
+ glyph.bitmap = glyph_pbf.string();
+ } else if (glyph_pbf.tag == 3) { // width
+ glyph.metrics.width = glyph_pbf.varint();
+ } else if (glyph_pbf.tag == 4) { // height
+ glyph.metrics.height = glyph_pbf.varint();
+ } else if (glyph_pbf.tag == 5) { // left
+ glyph.metrics.left = glyph_pbf.svarint();
+ } else if (glyph_pbf.tag == 6) { // top
+ glyph.metrics.top = glyph_pbf.svarint();
+ } else if (glyph_pbf.tag == 7) { // advance
+ glyph.metrics.advance = glyph_pbf.varint();
+ } else {
+ glyph_pbf.skip();
+ }
+ }
+
+ stack.insert(glyph.id, glyph);
+ } else {
+ fontstack_pbf.skip();
+ }
+ }
+ } else {
+ glyphs_pbf.skip();
+ }
+ }
+
+ data.clear();
+
+ parsed = true;
+}
+
+bool GlyphPBF::isParsed() const {
+ return parsed;
+}
+
+}
diff --git a/src/mbgl/text/glyph_pbf.hpp b/src/mbgl/text/glyph_pbf.hpp
new file mode 100644
index 0000000000..bb6fa83ae6
--- /dev/null
+++ b/src/mbgl/text/glyph_pbf.hpp
@@ -0,0 +1,52 @@
+#ifndef MBGL_TEXT_GLYPH_PBF
+#define MBGL_TEXT_GLYPH_PBF
+
+#include <mbgl/text/glyph.hpp>
+
+#include <functional>
+#include <atomic>
+#include <string>
+
+namespace mbgl {
+
+class Environment;
+class FontStack;
+class Request;
+
+class GlyphPBF {
+public:
+ using GlyphLoadedCallback = std::function<void(GlyphPBF*)>;
+ using GlyphLoadingFailedCallback = std::function<void(const std::string&)>;
+
+ GlyphPBF(const std::string &glyphURL,
+ const std::string &fontStack,
+ GlyphRange glyphRange,
+ Environment &env,
+ const GlyphLoadedCallback& successCallback,
+ const GlyphLoadingFailedCallback& failureCallback);
+ ~GlyphPBF();
+
+ void parse(FontStack &stack);
+ bool isParsed() const;
+
+ std::string getURL() const {
+ return url;
+ }
+
+private:
+ GlyphPBF(const GlyphPBF &) = delete;
+ GlyphPBF(GlyphPBF &&) = delete;
+ GlyphPBF &operator=(const GlyphPBF &) = delete;
+ GlyphPBF &operator=(GlyphPBF &&) = delete;
+
+ std::string data;
+ std::string url;
+ std::atomic<bool> parsed;
+
+ Environment& env;
+ Request* req = nullptr;
+};
+
+} // end namespace mbgl
+
+#endif
diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp
index 37e26b193c..9520b63c06 100644
--- a/src/mbgl/text/glyph_store.cpp
+++ b/src/mbgl/text/glyph_store.cpp
@@ -1,264 +1,19 @@
#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/text/glyph_pbf.hpp>
+#include <mbgl/text/font_stack.hpp>
-#include <mbgl/map/environment.hpp>
-#include <mbgl/util/std.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/util/utf.hpp>
-#include <mbgl/util/pbf.hpp>
-#include <mbgl/util/url.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/token.hpp>
-#include <mbgl/util/math.hpp>
+#include <mbgl/util/exception.hpp>
#include <mbgl/util/uv_detail.hpp>
-#include <mbgl/storage/file_source.hpp>
-#include <mbgl/platform/log.hpp>
-#include <mbgl/platform/platform.hpp>
-#include <mbgl/util/uv_detail.hpp>
-#include <algorithm>
namespace mbgl {
-
-void FontStack::insert(uint32_t id, const SDFGlyph &glyph) {
- std::lock_guard<std::mutex> lock(mtx);
- metrics.emplace(id, glyph.metrics);
- bitmaps.emplace(id, glyph.bitmap);
- sdfs.emplace(id, glyph);
-}
-
-const std::map<uint32_t, GlyphMetrics> &FontStack::getMetrics() const {
- std::lock_guard<std::mutex> lock(mtx);
- return metrics;
-}
-
-const std::map<uint32_t, SDFGlyph> &FontStack::getSDFs() const {
- std::lock_guard<std::mutex> lock(mtx);
- return sdfs;
-}
-
-const Shaping FontStack::getShaping(const std::u32string &string, const float maxWidth,
- const float lineHeight, const float horizontalAlign,
- const float verticalAlign, const float justify,
- const float spacing, const vec2<float> &translate) const {
- std::lock_guard<std::mutex> lock(mtx);
-
- Shaping shaping(translate.x * 24, translate.y * 24);
-
- // the y offset *should* be part of the font metadata
- const int32_t yOffset = -17;
-
- int32_t x = std::round(translate.x * 24); // one em
- const int32_t y = std::round(translate.y * 24) + yOffset; // one em
-
- // Loop through all characters of this label and shape.
- for (uint32_t chr : string) {
- shaping.positionedGlyphs.emplace_back(chr, x, y);
- auto metric = metrics.find(chr);
- if (metric != metrics.end()) {
- x += metric->second.advance + spacing;
- }
- }
-
- if (!shaping.positionedGlyphs.size())
- return shaping;
-
- lineWrap(shaping, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify);
-
- return shaping;
-}
-
-void align(Shaping &shaping, const float justify, const float horizontalAlign,
- const float verticalAlign, const uint32_t maxLineLength, const float lineHeight,
- const uint32_t line) {
- const float shiftX = (justify - horizontalAlign) * maxLineLength;
- const float shiftY = (-verticalAlign * (line + 1) + 0.5) * lineHeight;
-
- for (auto& glyph : shaping.positionedGlyphs) {
- glyph.x += shiftX;
- glyph.y += shiftY;
- }
-}
-
-void justifyLine(std::vector<PositionedGlyph> &positionedGlyphs, const std::map<uint32_t, GlyphMetrics> &metrics, uint32_t start,
- uint32_t end, float justify) {
- PositionedGlyph &glyph = positionedGlyphs[end];
- auto metric = metrics.find(glyph.glyph);
- if (metric != metrics.end()) {
- const uint32_t lastAdvance = metric->second.advance;
- const float lineIndent = float(glyph.x + lastAdvance) * justify;
-
- for (uint32_t j = start; j <= end; j++) {
- positionedGlyphs[j].x -= lineIndent;
- }
- }
-}
-
-void FontStack::lineWrap(Shaping &shaping, const float lineHeight, const float maxWidth,
- const float horizontalAlign, const float verticalAlign,
- const float justify) const {
- uint32_t lastSafeBreak = 0;
-
- uint32_t lengthBeforeCurrentLine = 0;
- uint32_t lineStartIndex = 0;
- uint32_t line = 0;
-
- uint32_t maxLineLength = 0;
-
- std::vector<PositionedGlyph> &positionedGlyphs = shaping.positionedGlyphs;
-
- if (maxWidth) {
- for (uint32_t i = 0; i < positionedGlyphs.size(); i++) {
- PositionedGlyph &shape = positionedGlyphs[i];
-
- shape.x -= lengthBeforeCurrentLine;
- shape.y += lineHeight * line;
-
- if (shape.x > maxWidth && lastSafeBreak > 0) {
-
- uint32_t lineLength = positionedGlyphs[lastSafeBreak + 1].x;
- maxLineLength = util::max(lineLength, maxLineLength);
-
- for (uint32_t k = lastSafeBreak + 1; k <= i; k++) {
- positionedGlyphs[k].y += lineHeight;
- positionedGlyphs[k].x -= lineLength;
- }
-
- if (justify) {
- justifyLine(positionedGlyphs, metrics, lineStartIndex, lastSafeBreak - 1, justify);
- }
-
- lineStartIndex = lastSafeBreak + 1;
- lastSafeBreak = 0;
- lengthBeforeCurrentLine += lineLength;
- line++;
- }
-
- if (shape.glyph == 32) {
- lastSafeBreak = i;
- }
- }
- }
-
- const PositionedGlyph& lastPositionedGlyph = positionedGlyphs.back();
- const auto lastGlyphMetric = metrics.find(lastPositionedGlyph.glyph);
- assert(lastGlyphMetric != metrics.end());
- const uint32_t lastLineLength = lastPositionedGlyph.x + lastGlyphMetric->second.advance;
- maxLineLength = std::max(maxLineLength, lastLineLength);
-
- const uint32_t height = (line + 1) * lineHeight;
-
- justifyLine(positionedGlyphs, metrics, lineStartIndex, uint32_t(positionedGlyphs.size()) - 1, justify);
- align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line);
-
- // Calculate the bounding box
- shaping.top += -verticalAlign * height;
- shaping.bottom = shaping.top + height;
- shaping.left += -horizontalAlign * maxLineLength;
- shaping.right = shaping.left + maxLineLength;
-}
-
-GlyphPBF::GlyphPBF(const std::string& glyphURL,
- const std::string& fontStack,
- GlyphRange glyphRange,
- Environment& env_,
- const GlyphLoadedCallback& callback)
- : parsed(false), env(env_) {
- // Load the glyph set URL
- std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string {
- if (name == "fontstack") return util::percentEncode(fontStack);
- if (name == "range") return util::toString(glyphRange.first) + "-" + util::toString(glyphRange.second);
- return "";
- });
-
- // The prepare call jumps back to the main thread.
- req = env.request({ Resource::Kind::Glyphs, url }, [&, url, callback](const Response &res) {
- req = nullptr;
-
- if (res.status != Response::Successful) {
- // Something went wrong with loading the glyph pbf.
- const std::string msg = std::string { "[ERROR] failed to load glyphs: " } + url + " message: " + res.message;
- Log::Error(Event::HttpRequest, msg);
- } else {
- // Transfer the data to the GlyphSet and signal its availability.
- // Once it is available, the caller will need to call parse() to actually
- // parse the data we received. We are not doing this here since this callback is being
- // called from another (unknown) thread.
- data = res.data;
- parsed = true;
- callback(this);
- }
- });
-}
-
-GlyphPBF::~GlyphPBF() {
- if (req) {
- env.cancelRequest(req);
- }
-}
-
-void GlyphPBF::parse(FontStack &stack) {
- std::lock_guard<std::mutex> lock(mtx);
-
- if (!data.size()) {
- // If there is no data, this means we either haven't received any data, or
- // we have already parsed the data.
- return;
- }
-
- // Parse the glyph PBF
- pbf glyphs_pbf(reinterpret_cast<const uint8_t *>(data.data()), data.size());
-
- while (glyphs_pbf.next()) {
- if (glyphs_pbf.tag == 1) { // stacks
- pbf fontstack_pbf = glyphs_pbf.message();
- while (fontstack_pbf.next()) {
- if (fontstack_pbf.tag == 3) { // glyphs
- pbf glyph_pbf = fontstack_pbf.message();
-
- SDFGlyph glyph;
-
- while (glyph_pbf.next()) {
- if (glyph_pbf.tag == 1) { // id
- glyph.id = glyph_pbf.varint();
- } else if (glyph_pbf.tag == 2) { // bitmap
- glyph.bitmap = glyph_pbf.string();
- } else if (glyph_pbf.tag == 3) { // width
- glyph.metrics.width = glyph_pbf.varint();
- } else if (glyph_pbf.tag == 4) { // height
- glyph.metrics.height = glyph_pbf.varint();
- } else if (glyph_pbf.tag == 5) { // left
- glyph.metrics.left = glyph_pbf.svarint();
- } else if (glyph_pbf.tag == 6) { // top
- glyph.metrics.top = glyph_pbf.svarint();
- } else if (glyph_pbf.tag == 7) { // advance
- glyph.metrics.advance = glyph_pbf.varint();
- } else {
- glyph_pbf.skip();
- }
- }
-
- stack.insert(glyph.id, glyph);
- } else {
- fontstack_pbf.skip();
- }
- }
- } else {
- glyphs_pbf.skip();
- }
- }
-
- data.clear();
-}
-
-bool GlyphPBF::isParsed() const {
- return parsed;
-}
-
GlyphStore::GlyphStore(uv_loop_t* loop, Environment& env_)
: env(env_),
- asyncEmitGlyphRangeLoaded(util::make_unique<uv::async>(loop, [this] { emitGlyphRangeLoaded(); })),
+ asyncEmitGlyphRangeLoaded(std::make_unique<uv::async>(loop, [this] { emitGlyphRangeLoaded(); })),
+ asyncEmitGlyphRangeLoadedingFailed(std::make_unique<uv::async>(loop, [this] { emitGlyphRangeLoadingFailed(); })),
observer(nullptr) {
asyncEmitGlyphRangeLoaded->unref();
+ asyncEmitGlyphRangeLoadedingFailed->unref();
}
GlyphStore::~GlyphStore() {
@@ -269,7 +24,7 @@ void GlyphStore::setURL(const std::string &url) {
glyphURL = url;
}
-bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStack,
+bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStackName,
const std::set<GlyphRange>& glyphRanges) {
bool requestIsNeeded = false;
@@ -277,18 +32,32 @@ bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStack,
return requestIsNeeded;
}
- auto callback = [this, fontStack](GlyphPBF* glyph) {
- glyph->parse(*createFontStack(fontStack));
- asyncEmitGlyphRangeLoaded->send();
+ auto successCallback = [this, fontStackName](GlyphPBF* glyph) {
+ auto fontStack = createFontStack(fontStackName);
+ try {
+ glyph->parse(**fontStack);
+ asyncEmitGlyphRangeLoaded->send();
+ } catch (const std::exception&) {
+ std::lock_guard<std::mutex> lock(errorMessageMutex);
+ errorMessage = "Failed to parse [" + glyph->getURL() + "]";
+ asyncEmitGlyphRangeLoadedingFailed->send();
+ }
+ };
+
+ auto failureCallback = [this](const std::string& message) {
+ std::lock_guard<std::mutex> lock(errorMessageMutex);
+ errorMessage = message;
+ asyncEmitGlyphRangeLoadedingFailed->send();
};
std::lock_guard<std::mutex> lock(rangesMutex);
- auto& rangeSets = ranges[fontStack];
+ auto& rangeSets = ranges[fontStackName];
for (const auto& range : glyphRanges) {
const auto& rangeSets_it = rangeSets.find(range);
if (rangeSets_it == rangeSets.end()) {
- auto glyph = util::make_unique<GlyphPBF>(glyphURL, fontStack, range, env, callback);
+ auto glyph = std::make_unique<GlyphPBF>(glyphURL, fontStackName, range, env,
+ successCallback, failureCallback);
rangeSets.emplace(range, std::move(glyph));
requestIsNeeded = true;
continue;
@@ -302,26 +71,26 @@ bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStack,
return requestIsNeeded;
}
-FontStack* GlyphStore::createFontStack(const std::string &fontStack) {
- std::lock_guard<std::mutex> lock(stacksMutex);
+util::exclusive<FontStack> GlyphStore::createFontStack(const std::string &fontStack) {
+ auto lock = std::make_unique<std::lock_guard<std::mutex>>(stacksMutex);
auto stack_it = stacks.find(fontStack);
if (stack_it == stacks.end()) {
- stack_it = stacks.emplace(fontStack, util::make_unique<FontStack>()).first;
+ stack_it = stacks.emplace(fontStack, std::make_unique<FontStack>()).first;
}
- return stack_it->second.get();
+ return { stack_it->second.get(), std::move(lock) };
}
-FontStack* GlyphStore::getFontStack(const std::string &fontStack) {
- std::lock_guard<std::mutex> lock(stacksMutex);
+util::exclusive<FontStack> GlyphStore::getFontStack(const std::string &fontStack) {
+ auto lock = std::make_unique<std::lock_guard<std::mutex>>(stacksMutex);
const auto& stack_it = stacks.find(fontStack);
if (stack_it == stacks.end()) {
- return nullptr;
+ return { nullptr, nullptr };
}
- return stack_it->second.get();
+ return { stack_it->second.get(), std::move(lock) };
}
void GlyphStore::setObserver(Observer* observer_) {
@@ -334,4 +103,14 @@ void GlyphStore::emitGlyphRangeLoaded() {
}
}
+void GlyphStore::emitGlyphRangeLoadingFailed() {
+ if (!observer) {
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(errorMessageMutex);
+ auto error = std::make_exception_ptr(util::GlyphRangeLoadingException(errorMessage));
+ observer->onGlyphRangeLoadingFailed(error);
+}
+
}
diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp
index efa848dd08..746bcd1338 100644
--- a/src/mbgl/text/glyph_store.hpp
+++ b/src/mbgl/text/glyph_store.hpp
@@ -2,90 +2,27 @@
#define MBGL_TEXT_GLYPH_STORE
#include <mbgl/text/glyph.hpp>
-#include <mbgl/util/vec.hpp>
-#include <mbgl/util/ptr.hpp>
-#include <cstdint>
-#include <vector>
-#include <future>
-#include <map>
+#include <mbgl/util/exclusive.hpp>
+
#include <set>
#include <string>
#include <unordered_map>
+#include <exception>
typedef struct uv_loop_s uv_loop_t;
namespace uv {
-
class async;
-
}
namespace mbgl {
-class FileSource;
class Environment;
-class Request;
-
-class SDFGlyph {
-public:
- uint32_t id = 0;
-
- // A signed distance field of the glyph with a border of 3 pixels.
- std::string bitmap;
-
- // Glyph metrics
- GlyphMetrics metrics;
-};
-
-class FontStack {
-public:
- void insert(uint32_t id, const SDFGlyph &glyph);
- const std::map<uint32_t, GlyphMetrics> &getMetrics() const;
- const std::map<uint32_t, SDFGlyph> &getSDFs() const;
- const Shaping getShaping(const std::u32string &string, float maxWidth, float lineHeight,
- float horizontalAlign, float verticalAlign, float justify,
- float spacing, const vec2<float> &translate) const;
- void lineWrap(Shaping &shaping, float lineHeight, float maxWidth, float horizontalAlign,
- float verticalAlign, float justify) const;
-
-private:
- std::map<uint32_t, std::string> bitmaps;
- std::map<uint32_t, GlyphMetrics> metrics;
- std::map<uint32_t, SDFGlyph> sdfs;
- mutable std::mutex mtx;
-};
-
-class GlyphPBF {
-public:
- using GlyphLoadedCallback = std::function<void(GlyphPBF*)>;
-
- GlyphPBF(const std::string &glyphURL,
- const std::string &fontStack,
- GlyphRange glyphRange,
- Environment &env,
- const GlyphLoadedCallback& callback);
- ~GlyphPBF();
-
- void parse(FontStack &stack);
- bool isParsed() const;
-
-private:
- GlyphPBF(const GlyphPBF &) = delete;
- GlyphPBF(GlyphPBF &&) = delete;
- GlyphPBF &operator=(const GlyphPBF &) = delete;
- GlyphPBF &operator=(GlyphPBF &&) = delete;
-
- std::string data;
- std::atomic_bool parsed;
-
- Environment& env;
- Request* req = nullptr;
+class FontStack;
+class GlyphPBF;
- mutable std::mutex mtx;
-};
-
-// Manages Glyphrange PBF loading.
+// Manages GlyphRange PBF loading.
class GlyphStore {
public:
class Observer {
@@ -93,6 +30,7 @@ public:
virtual ~Observer() = default;
virtual void onGlyphRangeLoaded() = 0;
+ virtual void onGlyphRangeLoadingFailed(std::exception_ptr error) = 0;
};
GlyphStore(uv_loop_t* loop, Environment &);
@@ -104,7 +42,7 @@ public:
// GlyphRanges are already available, and thus, no request is performed.
bool requestGlyphRangesIfNeeded(const std::string &fontStack, const std::set<GlyphRange> &glyphRanges);
- FontStack* getFontStack(const std::string &fontStack);
+ util::exclusive<FontStack> getFontStack(const std::string &fontStack);
void setURL(const std::string &url);
@@ -112,8 +50,9 @@ public:
private:
void emitGlyphRangeLoaded();
+ void emitGlyphRangeLoadingFailed();
- FontStack* createFontStack(const std::string &fontStack);
+ util::exclusive<FontStack> createFontStack(const std::string &fontStack);
std::string glyphURL;
Environment &env;
@@ -124,7 +63,11 @@ private:
std::unordered_map<std::string, std::unique_ptr<FontStack>> stacks;
std::mutex stacksMutex;
+ std::string errorMessage;
+ std::mutex errorMessageMutex;
+
std::unique_ptr<uv::async> asyncEmitGlyphRangeLoaded;
+ std::unique_ptr<uv::async> asyncEmitGlyphRangeLoadedingFailed;
Observer* observer;
};
diff --git a/src/mbgl/util/raster.cpp b/src/mbgl/util/raster.cpp
index f2171a6165..b6b5df27f6 100644
--- a/src/mbgl/util/raster.cpp
+++ b/src/mbgl/util/raster.cpp
@@ -4,7 +4,6 @@
#include <mbgl/util/raster.hpp>
#include <mbgl/util/uv_detail.hpp>
-#include <mbgl/util/std.hpp>
#include <cassert>
#include <cstring>
@@ -27,7 +26,7 @@ bool Raster::isLoaded() const {
}
bool Raster::load(const std::string &data) {
- img = util::make_unique<util::Image>(data);
+ img = std::make_unique<util::Image>(data);
width = img->getWidth();
height = img->getHeight();
diff --git a/src/mbgl/util/run_loop.hpp b/src/mbgl/util/run_loop.hpp
index ed2b364cef..1c92847b69 100644
--- a/src/mbgl/util/run_loop.hpp
+++ b/src/mbgl/util/run_loop.hpp
@@ -2,10 +2,10 @@
#define MBGL_UTIL_RUN_LOOP
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <functional>
+#include <utility>
#include <queue>
#include <mutex>
@@ -19,37 +19,38 @@ public:
void stop();
- // Invoke fn() in the runloop thread.
- template <class Fn>
- void invoke(Fn&& fn) {
- auto invokable = util::make_unique<Invoker<Fn>>(std::move(fn));
+ // Invoke fn(args...) on this RunLoop.
+ template <class Fn, class... Args>
+ void invoke(Fn&& fn, Args&&... args) {
+ auto tuple = std::make_tuple(std::move(args)...);
+ auto invokable = std::make_unique<Invoker<Fn, decltype(tuple), Args...>>(std::move(fn), std::move(tuple));
withMutex([&] { queue.push(std::move(invokable)); });
async.send();
}
- // Invoke fn() in the runloop thread, then invoke callback(result) in the current thread.
- template <class Fn, class R>
- void invokeWithResult(Fn&& fn, std::function<void (R)>&& callback) {
- RunLoop* outer = current.get();
- assert(outer);
-
- invoke([fn = std::move(fn), callback = std::move(callback), outer] () mutable {
- outer->invoke([callback = std::move(callback), result = std::move(fn())] () mutable {
- callback(std::move(result));
- });
- });
+ // Return a function that invokes the given function on this RunLoop.
+ template <class... Args>
+ auto bind(std::function<void (Args...)> fn) {
+ return [this, fn = std::move(fn)] (Args&&... args) {
+ invoke(std::move(fn), std::move(args)...);
+ };
}
- // Invoke fn() in the runloop thread, then invoke callback() in the current thread.
- template <class Fn>
- void invokeWithResult(Fn&& fn, std::function<void ()>&& callback) {
- RunLoop* outer = current.get();
- assert(outer);
+ // Invoke fn(args...) on this RunLoop, then invoke callback(result) on the current RunLoop.
+ template <class R, class Fn, class... Args>
+ void invokeWithResult(Fn&& fn, std::function<void (R)> callback, Args&&... args) {
+ invoke([fn = std::move(fn), callback = current.get()->bind(callback)] (Args&&... a) mutable {
+ callback(fn(std::forward<Args>(a)...));
+ }, std::forward<Args>(args)...);
+ }
- invoke([fn = std::move(fn), callback = std::move(callback), outer] () mutable {
- fn();
- outer->invoke(std::move(callback));
- });
+ // Invoke fn(args...) on this RunLoop, then invoke callback() on the current RunLoop.
+ template <class Fn, class... Args>
+ void invokeWithResult(Fn&& fn, std::function<void ()> callback, Args&&... args) {
+ invoke([fn = std::move(fn), callback = current.get()->bind(callback)] (Args&&... a) mutable {
+ fn(std::forward<Args>(a)...);
+ callback();
+ }, std::forward<Args>(args)...);
}
uv_loop_t* get() { return async.get()->loop; }
@@ -65,11 +66,24 @@ private:
virtual ~Message() = default;
};
- template <class F>
+ template <class F, class P, class... Args>
struct Invoker : Message {
- Invoker(F&& f) : func(std::move(f)) {}
- void operator()() override { func(); }
+ Invoker(F&& f, P&& p)
+ : func(std::move(f)),
+ params(std::move(p)) {
+ }
+
+ void operator()() override {
+ invoke(std::index_sequence_for<Args...>{});
+ }
+
+ template <std::size_t... I>
+ void invoke(std::index_sequence<I...>) {
+ func(std::forward<Args>(std::get<I>(params))...);
+ }
+
F func;
+ P params;
};
using Queue = std::queue<std::unique_ptr<Message>>;
diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp
index a2ad958645..f3a9baa6f3 100644
--- a/src/mbgl/util/thread.hpp
+++ b/src/mbgl/util/thread.hpp
@@ -4,26 +4,12 @@
#include <future>
#include <thread>
#include <atomic>
+#include <utility>
#include <functional>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/platform/platform.hpp>
-namespace {
-
-template <::std::size_t...>
-struct index_sequence {};
-
-template <::std::size_t N, ::std::size_t... I>
-struct integer_sequence : integer_sequence<N - 1, N - 1, I...> {};
-
-template <::std::size_t... I>
-struct integer_sequence<0, I...> {
- using type = index_sequence<I...>;
-};
-
-}
-
namespace mbgl {
namespace util {
@@ -50,19 +36,19 @@ public:
// Invoke object->fn(args...) in the runloop thread.
template <typename Fn, class... Args>
void invoke(Fn fn, Args&&... args) {
- loop->invoke(std::bind(fn, object, args...));
+ loop->invoke(bind<Fn, Args...>(fn), std::forward<Args>(args)...);
}
// Invoke object->fn(args...) in the runloop thread, then invoke callback(result) in the current thread.
- template <typename Fn, class R, class... Args>
- void invokeWithResult(Fn fn, std::function<void (R)>&& callback, Args&&... args) {
- loop->invokeWithResult(std::bind(fn, object, std::move(args)...), std::move(callback));
+ template <class R, typename Fn, class... Args>
+ void invokeWithResult(Fn fn, std::function<void (R)> callback, Args&&... args) {
+ loop->invokeWithResult(bind<Fn, Args...>(fn), callback, std::forward<Args>(args)...);
}
// Invoke object->fn(args...) in the runloop thread, then invoke callback() in the current thread.
template <typename Fn, class... Args>
- void invokeWithResult(Fn fn, std::function<void ()>&& callback, Args&&... args) {
- loop->invokeWithResult(std::bind(fn, object, std::move(args)...), std::move(callback));
+ void invokeWithResult(Fn fn, std::function<void ()> callback, Args&&... args) {
+ loop->invokeWithResult(bind<Fn, Args...>(fn), callback, std::forward<Args>(args)...);
}
// Invoke object->fn(args...) in the runloop thread, and wait for the result.
@@ -89,8 +75,13 @@ private:
Thread& operator=(const Thread&) = delete;
Thread& operator=(Thread&&) = delete;
+ template <typename Fn, class... Args>
+ auto bind(Fn fn) {
+ return [fn, this] (Args&&... a) { return (object->*fn)(std::forward<Args>(a)...); };
+ }
+
template <typename P, std::size_t... I>
- void run(P&& params, index_sequence<I...>);
+ void run(P&& params, std::index_sequence<I...>);
std::promise<void> running;
std::promise<void> joinable;
@@ -119,8 +110,7 @@ Thread<Object>::Thread(const std::string& name, ThreadPriority priority, Args&&.
platform::makeThreadLowPriority();
}
- constexpr auto seq = typename integer_sequence<sizeof...(Args)>::type();
- run(std::move(params), seq);
+ run(std::move(params), std::index_sequence_for<Args...>{});
});
running.get_future().get();
@@ -128,7 +118,7 @@ Thread<Object>::Thread(const std::string& name, ThreadPriority priority, Args&&.
template <class Object>
template <typename P, std::size_t... I>
-void Thread<Object>::run(P&& params, index_sequence<I...>) {
+void Thread<Object>::run(P&& params, std::index_sequence<I...>) {
uv::loop l;
{
diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp
index 984c55c95e..3022d30277 100644
--- a/src/mbgl/util/worker.cpp
+++ b/src/mbgl/util/worker.cpp
@@ -19,7 +19,7 @@ public:
Worker::Worker(std::size_t count) {
for (std::size_t i = 0; i < count; i++) {
- threads.emplace_back(util::make_unique<util::Thread<Impl>>("Worker", util::ThreadPriority::Low));
+ threads.emplace_back(std::make_unique<util::Thread<Impl>>("Worker", util::ThreadPriority::Low));
}
}
@@ -27,7 +27,7 @@ Worker::~Worker() = default;
std::unique_ptr<WorkRequest> Worker::send(Fn work, Fn after) {
auto task = std::make_shared<WorkTask>(work, after);
- auto request = util::make_unique<WorkRequest>(task);
+ auto request = std::make_unique<WorkRequest>(task);
threads[current]->invokeWithResult(&Worker::Impl::doWork, [task] {
task->runAfter();