diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mbgl/map/environment.cpp | 39 | ||||
-rw-r--r-- | src/mbgl/map/environment.hpp | 44 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 40 | ||||
-rw-r--r-- | src/mbgl/map/raster_tile_data.cpp | 7 | ||||
-rw-r--r-- | src/mbgl/map/raster_tile_data.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/source.cpp | 47 | ||||
-rw-r--r-- | src/mbgl/map/source.hpp | 22 | ||||
-rw-r--r-- | src/mbgl/map/sprite.cpp | 22 | ||||
-rw-r--r-- | src/mbgl/map/sprite.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/map/tile_data.cpp | 15 | ||||
-rw-r--r-- | src/mbgl/map/tile_data.hpp | 8 | ||||
-rw-r--r-- | src/mbgl/map/vector_tile_data.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/map/vector_tile_data.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/storage/default_file_source.cpp | 62 | ||||
-rw-r--r-- | src/mbgl/storage/request.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/text/glyph_store.cpp | 15 | ||||
-rw-r--r-- | src/mbgl/text/glyph_store.hpp | 10 |
17 files changed, 235 insertions, 120 deletions
diff --git a/src/mbgl/map/environment.cpp b/src/mbgl/map/environment.cpp new file mode 100644 index 0000000000..ee13d33ea7 --- /dev/null +++ b/src/mbgl/map/environment.cpp @@ -0,0 +1,39 @@ +#include <mbgl/map/environment.hpp> +#include <mbgl/storage/file_source.hpp> + +#include <uv.h> + +#include <cassert> + +namespace mbgl { + +Environment::Environment(FileSource &fs) : fileSource(fs), loop(uv_loop_new()) { +} + +void Environment::setup() { + mapThread = std::this_thread::get_id(); +} + +bool Environment::inMapThread() const { + return std::this_thread::get_id() == mapThread; +} + +void Environment::requestAsync(const Resource &resource, std::function<void(const Response &)> callback) { + fileSource.request(resource, *this, std::move(callback)); +} + +Request *Environment::request(const Resource &resource, std::function<void(const Response &)> callback) { + assert(inMapThread()); + return fileSource.request(resource, loop, *this, std::move(callback)); +} + +void Environment::cancelRequest(Request *req) { + assert(inMapThread()); + fileSource.cancel(req); +} + +void Environment::terminate() { + fileSource.abort(*this); +} + +} diff --git a/src/mbgl/map/environment.hpp b/src/mbgl/map/environment.hpp new file mode 100644 index 0000000000..b68a7b9e2f --- /dev/null +++ b/src/mbgl/map/environment.hpp @@ -0,0 +1,44 @@ +#ifndef MBGL_MAP_MAP_ENVIRONMENT +#define MBGL_MAP_MAP_ENVIRONMENT + +#include <mbgl/util/noncopyable.hpp> +#include <mbgl/util/util.hpp> + +#include <thread> +#include <functional> + +typedef struct uv_loop_s uv_loop_t; + +namespace mbgl { + +class FileSource; +class Request; +class Response; +struct Resource; + +class Environment : private util::noncopyable { +public: + Environment(FileSource &); + + void setup(); + + bool inMapThread() const; + + void requestAsync(const Resource &, std::function<void(const Response &)>); + Request *request(const Resource &, std::function<void(const Response &)>); + void cancelRequest(Request *); + + // Request to terminate the environment. + void terminate(); + +private: + FileSource &fileSource; + std::thread::id mapThread; + +public: + uv_loop_t *const loop; +}; + +} + +#endif diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 518bc5bb96..0cd7d3621e 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -1,4 +1,5 @@ #include <mbgl/map/map.hpp> +#include <mbgl/map/environment.hpp> #include <mbgl/map/view.hpp> #include <mbgl/platform/platform.hpp> #include <mbgl/map/source.hpp> @@ -25,6 +26,7 @@ #include <mbgl/util/string.hpp> #include <mbgl/util/uv.hpp> #include <mbgl/util/mapbox.hpp> +#include <mbgl/util/exception.hpp> #include <algorithm> #include <iostream> @@ -57,16 +59,14 @@ const static bool uvVersionCheck = []() { using namespace mbgl; Map::Map(View& view_, FileSource& fileSource_) - : loop(util::make_unique<uv::loop>()), + : env(util::make_unique<Environment>(fileSource_)), view(view_), -#ifdef DEBUG mainThread(std::this_thread::get_id()), mapThread(mainThread), -#endif transform(view_), fileSource(fileSource_), glyphAtlas(util::make_unique<GlyphAtlas>(1024, 1024)), - glyphStore(std::make_shared<GlyphStore>(fileSource)), + glyphStore(std::make_shared<GlyphStore>(*env)), spriteAtlas(util::make_unique<SpriteAtlas>(512, 512)), lineAtlas(util::make_unique<LineAtlas>(512, 512)), texturePool(std::make_shared<TexturePool>()), @@ -92,7 +92,7 @@ Map::~Map() { texturePool.reset(); workers.reset(); - uv_run(**loop, UV_RUN_DEFAULT); + uv_run(env->loop, UV_RUN_DEFAULT); } uv::worker &Map::getWorker() { @@ -112,7 +112,7 @@ void Map::start(bool startPaused) { isStopped = false; // Setup async notifications - asyncTerminate = util::make_unique<uv::async>(**loop, [this]() { + asyncTerminate = util::make_unique<uv::async>(env->loop, [this]() { assert(std::this_thread::get_id() == mapThread); // Remove all of these to make sure they are destructed in the correct thread. @@ -127,7 +127,7 @@ void Map::start(bool startPaused) { asyncTerminate.reset(); }); - asyncRender = util::make_unique<uv::async>(**loop, [this]() { + asyncRender = util::make_unique<uv::async>(env->loop, [this]() { assert(std::this_thread::get_id() == mapThread); if (state.hasSize()) { @@ -207,7 +207,7 @@ void Map::pause(bool waitForPause) { pausing = true; mutexRun.unlock(); - uv_stop(**loop); + uv_stop(env->loop); rerender(); // Needed to ensure uv_stop is seen and uv_run exits, otherwise we deadlock on wait_for_pause if (waitForPause) { @@ -242,12 +242,14 @@ void Map::run() { } if (mode == Mode::Static && !style && styleURL.empty()) { - throw exception("Style is not set"); + throw util::Exception("Style is not set"); } view.activate(); - workers = util::make_unique<uv::worker>(**loop, 4, "Tile Worker"); + workers = util::make_unique<uv::worker>(env->loop, 4, "Tile Worker"); + + env->setup(); setup(); prepare(); @@ -255,15 +257,15 @@ void Map::run() { if (mode == Mode::Continuous) { terminating = false; while(!terminating) { - uv_run(**loop, UV_RUN_DEFAULT); + uv_run(env->loop, UV_RUN_DEFAULT); checkForPause(); } } else { - uv_run(**loop, UV_RUN_DEFAULT); + uv_run(env->loop, UV_RUN_DEFAULT); } // Run the event loop once more to make sure our async delete handlers are called. - uv_run(**loop, UV_RUN_ONCE); + uv_run(env->loop, UV_RUN_ONCE); // If the map rendering wasn't started asynchronously, we perform one render // *after* all events have been processed. @@ -376,7 +378,7 @@ util::ptr<Sprite> Map::getSprite() { const float pixelRatio = state.getPixelRatio(); const std::string &sprite_url = style->getSpriteURL(); if (!sprite || sprite->pixelRatio != pixelRatio) { - sprite = Sprite::Create(sprite_url, pixelRatio, fileSource); + sprite = Sprite::Create(sprite_url, pixelRatio, *env); } return sprite; @@ -621,7 +623,7 @@ void Map::updateSources() { if (source->enabled) { if (!source->source) { source->source = std::make_shared<Source>(source->info); - source->source->load(*this, fileSource); + source->source->load(*this, *env); } } else { source->source.reset(); @@ -648,10 +650,8 @@ void Map::updateSources(const util::ptr<StyleLayerGroup> &group) { void Map::updateTiles() { for (const auto& source : activeSources) { - source->source->update(*this, getWorker(), - style, *glyphAtlas, *glyphStore, - *spriteAtlas, getSprite(), - *texturePool, fileSource, ***loop, [this](){ update(); }); + source->source->update(*this, *env, getWorker(), style, *glyphAtlas, *glyphStore, + *spriteAtlas, getSprite(), *texturePool, [this]() { update(); }); } } @@ -659,7 +659,7 @@ void Map::prepare() { if (!style) { style = std::make_shared<Style>(); - fileSource.request({ Resource::Kind::JSON, styleURL}, **loop, [&](const Response &res) { + env->request({ Resource::Kind::JSON, styleURL}, [&](const Response &res) { if (res.status == Response::Successful) { // Calculate the base const size_t pos = styleURL.rfind('/'); diff --git a/src/mbgl/map/raster_tile_data.cpp b/src/mbgl/map/raster_tile_data.cpp index 1ca9ef8041..4cd7fc2b5e 100644 --- a/src/mbgl/map/raster_tile_data.cpp +++ b/src/mbgl/map/raster_tile_data.cpp @@ -4,10 +4,9 @@ using namespace mbgl; - -RasterTileData::RasterTileData(Tile::ID const& id_, TexturePool& texturePool, const SourceInfo& source_, FileSource& fileSource_) - : TileData(id_, source_, fileSource_), - bucket(texturePool, layout) { +RasterTileData::RasterTileData(Tile::ID const &id_, TexturePool &texturePool, + const SourceInfo &source_, Environment &env_) + : TileData(id_, source_, env_), bucket(texturePool, layout) { } RasterTileData::~RasterTileData() { diff --git a/src/mbgl/map/raster_tile_data.hpp b/src/mbgl/map/raster_tile_data.hpp index 9a8578a61e..2413e13fb0 100644 --- a/src/mbgl/map/raster_tile_data.hpp +++ b/src/mbgl/map/raster_tile_data.hpp @@ -17,7 +17,7 @@ class RasterTileData : public TileData { friend class TileParser; public: - RasterTileData(Tile::ID const& id, TexturePool&, const SourceInfo&, FileSource &); + RasterTileData(Tile::ID const &id, TexturePool &, const SourceInfo &, Environment &); ~RasterTileData(); void parse() override; diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index d9236b19b3..ec3a1b8e00 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -1,12 +1,14 @@ #include <mbgl/map/source.hpp> #include <mbgl/map/map.hpp> +#include <mbgl/map/environment.hpp> #include <mbgl/map/transform.hpp> #include <mbgl/renderer/painter.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/raster.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/texture_pool.hpp> -#include <mbgl/storage/file_source.hpp> +#include <mbgl/storage/resource.hpp> +#include <mbgl/storage/response.hpp> #include <mbgl/util/vec.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/std.hpp> @@ -32,7 +34,7 @@ Source::Source(SourceInfo& info_) // 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(Map& map, FileSource& fileSource) { +void Source::load(Map &map, Environment &env) { if (info.url.empty()) { loaded = true; return; @@ -41,7 +43,7 @@ void Source::load(Map& map, FileSource& fileSource) { util::ptr<Source> source = shared_from_this(); const std::string url = util::mapbox::normalizeSourceURL(info.url, map.getAccessToken()); - fileSource.request({ Resource::Kind::JSON, url }, **map.loop, [source, &map](const Response &res) { + env.request({ Resource::Kind::JSON, url }, [source, &map](const Response &res) { if (res.status != Response::Successful) { Log::Warning(Event::General, "Failed to load source TileJSON: %s", res.message.c_str()); return; @@ -153,13 +155,11 @@ TileData::State Source::hasTile(const Tile::ID& id) { return TileData::State::invalid; } -TileData::State Source::addTile(Map& map, uv::worker& worker, - util::ptr<Style> style, - GlyphAtlas& glyphAtlas, GlyphStore& glyphStore, - SpriteAtlas& spriteAtlas, util::ptr<Sprite> sprite, - FileSource& fileSource, uv_loop_t &loop, TexturePool& texturePool, - const Tile::ID& id, - std::function<void ()> callback) { +TileData::State Source::addTile(Map &map, Environment &env, uv::worker &worker, + util::ptr<Style> style, GlyphAtlas &glyphAtlas, + GlyphStore &glyphStore, SpriteAtlas &spriteAtlas, + util::ptr<Sprite> sprite, TexturePool &texturePool, + const Tile::ID &id, std::function<void()> callback) { const TileData::State state = hasTile(id); if (state != TileData::State::invalid) { @@ -190,14 +190,14 @@ TileData::State Source::addTile(Map& map, uv::worker& worker, new_tile.data = std::make_shared<VectorTileData>(normalized_id, map.getMaxZoom(), style, glyphAtlas, glyphStore, spriteAtlas, sprite, - info, fileSource); + info, env); } else if (info.type == SourceType::Raster) { - new_tile.data = std::make_shared<RasterTileData>(normalized_id, texturePool, info, fileSource); + new_tile.data = std::make_shared<RasterTileData>(normalized_id, texturePool, info, env); } else { throw std::runtime_error("source type not implemented"); } - new_tile.data->request(worker, loop, map.getState().getPixelRatio(), callback); + new_tile.data->request(worker, map.getState().getPixelRatio(), callback); tile_data.emplace(new_tile.data->id, new_tile.data); } @@ -283,12 +283,16 @@ bool Source::findLoadedParent(const Tile::ID& id, int32_t minCoveringZoom, std:: return false; } -void Source::update(Map& map, uv::worker& worker, +void Source::update(Map &map, + Environment &env, + uv::worker &worker, util::ptr<Style> style, - GlyphAtlas& glyphAtlas, GlyphStore& glyphStore, - SpriteAtlas& spriteAtlas, util::ptr<Sprite> sprite, - TexturePool& texturePool, FileSource& fileSource, uv_loop_t& loop, - std::function<void ()> callback) { + GlyphAtlas &glyphAtlas, + GlyphStore &glyphStore, + SpriteAtlas &spriteAtlas, + util::ptr<Sprite> sprite, + TexturePool &texturePool, + std::function<void()> callback) { if (!loaded || map.getTime() <= updated) return; @@ -308,11 +312,8 @@ void Source::update(Map& map, uv::worker& worker, // Add existing child/parent tiles if the actual tile is not yet loaded for (const Tile::ID& id : required) { - const TileData::State state = addTile(map, worker, style, - glyphAtlas, glyphStore, - spriteAtlas, sprite, - fileSource, loop, texturePool, - id, callback); + const TileData::State state = addTile(map, env, worker, style, glyphAtlas, glyphStore, + spriteAtlas, sprite, texturePool, id, callback); if (state != TileData::State::parsed) { // The tile we require is not yet loaded. Try to find a parent or diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index 2c0e444225..061908b89d 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -18,11 +18,11 @@ namespace mbgl { class Map; +class Environment; class GlyphAtlas; class GlyphStore; class SpriteAtlas; class Sprite; -class FileSource; class TexturePool; class Style; class Painter; @@ -34,13 +34,9 @@ class Source : public std::enable_shared_from_this<Source>, private util::noncop public: Source(SourceInfo&); - void load(Map&, FileSource&); - void update(Map&, uv::worker&, - util::ptr<Style>, - GlyphAtlas&, GlyphStore&, - SpriteAtlas&, util::ptr<Sprite>, - TexturePool&, FileSource&, uv_loop_t& loop, - std::function<void ()> callback); + void load(Map &, Environment &); + void update(Map &, Environment &, uv::worker &, util::ptr<Style>, GlyphAtlas &, GlyphStore &, + SpriteAtlas &, util::ptr<Sprite>, TexturePool &, std::function<void()> callback); void updateMatrices(const mat4 &projMatrix, const TransformState &transform); void drawClippingMasks(Painter &painter); @@ -59,13 +55,9 @@ private: int32_t coveringZoomLevel(const TransformState&) const; std::forward_list<Tile::ID> coveringTiles(const TransformState&) const; - TileData::State addTile(Map&, uv::worker&, - util::ptr<Style>, - GlyphAtlas&, GlyphStore&, - SpriteAtlas&, util::ptr<Sprite>, - FileSource&, uv_loop_t &, TexturePool&, - const Tile::ID&, - std::function<void ()> callback); + TileData::State addTile(Map &, Environment &, uv::worker &, util::ptr<Style>, GlyphAtlas &, + GlyphStore &, SpriteAtlas &, util::ptr<Sprite>, TexturePool &, + const Tile::ID &, std::function<void()> callback); TileData::State hasTile(const Tile::ID& id); diff --git a/src/mbgl/map/sprite.cpp b/src/mbgl/map/sprite.cpp index 9543fe083a..4be92ff73f 100644 --- a/src/mbgl/map/sprite.cpp +++ b/src/mbgl/map/sprite.cpp @@ -5,7 +5,9 @@ #include <string> #include <mbgl/platform/platform.hpp> -#include <mbgl/storage/file_source.hpp> +#include <mbgl/map/environment.hpp> +#include <mbgl/storage/resource.hpp> +#include <mbgl/storage/response.hpp> #include <mbgl/util/uv_detail.hpp> #include <mbgl/util/std.hpp> @@ -22,9 +24,9 @@ SpritePosition::SpritePosition(uint16_t x_, uint16_t y_, uint16_t width_, uint16 sdf(sdf_) { } -util::ptr<Sprite> Sprite::Create(const std::string& base_url, float pixelRatio, FileSource& fileSource) { +util::ptr<Sprite> Sprite::Create(const std::string &base_url, float pixelRatio, Environment &env) { util::ptr<Sprite> sprite(std::make_shared<Sprite>(Key(), base_url, pixelRatio)); - sprite->load(fileSource); + sprite->load(env); return sprite; } @@ -51,7 +53,7 @@ Sprite::operator bool() 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 Sprite::load(FileSource& fileSource) { +void Sprite::load(Environment &env) { if (!valid) { // Treat a non-existent sprite as a successfully loaded empty sprite. @@ -63,29 +65,25 @@ void Sprite::load(FileSource& fileSource) { util::ptr<Sprite> sprite = shared_from_this(); - fileSource.request({ Resource::Kind::JSON, jsonURL }, [sprite](const Response &res) { + env.request({ Resource::Kind::JSON, jsonURL }, [sprite](const Response &res) { if (res.status == Response::Successful) { sprite->body = res.data; sprite->parseJSON(); sprite->complete(); } else { Log::Warning(Event::Sprite, "Failed to load sprite info: %s", res.message.c_str()); - if (!sprite->future.valid()) { - sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message))); - } + sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message))); } }); - fileSource.request({ Resource::Kind::Image, spriteURL }, [sprite](const Response &res) { + env.request({ Resource::Kind::Image, spriteURL }, [sprite](const Response &res) { if (res.status == Response::Successful) { sprite->image = res.data; sprite->parseImage(); sprite->complete(); } else { Log::Warning(Event::Sprite, "Failed to load sprite image: %s", res.message.c_str()); - if (!sprite->future.valid()) { - sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message))); - } + sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message))); } }); } diff --git a/src/mbgl/map/sprite.hpp b/src/mbgl/map/sprite.hpp index d4b54ba1b5..cb0c274dee 100644 --- a/src/mbgl/map/sprite.hpp +++ b/src/mbgl/map/sprite.hpp @@ -14,7 +14,7 @@ namespace mbgl { -class FileSource; +class Environment; class SpritePosition { public: @@ -34,11 +34,12 @@ public: class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncopyable { private: struct Key {}; - void load(FileSource& fileSource); + void load(Environment &env); public: Sprite(const Key &, const std::string& base_url, float pixelRatio); - static util::ptr<Sprite> Create(const std::string& base_url, float pixelRatio, FileSource& fileSource); + static util::ptr<Sprite> + Create(const std::string &base_url, float pixelRatio, Environment &env); const SpritePosition &getSpritePosition(const std::string& name) const; diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp index 9d48041239..53d36dfe8b 100644 --- a/src/mbgl/map/tile_data.cpp +++ b/src/mbgl/map/tile_data.cpp @@ -1,5 +1,6 @@ #include <mbgl/map/tile_data.hpp> #include <mbgl/map/map.hpp> +#include <mbgl/map/environment.hpp> #include <mbgl/style/style_source.hpp> #include <mbgl/util/token.hpp> @@ -10,12 +11,12 @@ using namespace mbgl; -TileData::TileData(Tile::ID const& id_, const SourceInfo& source_, FileSource& fileSource_) +TileData::TileData(Tile::ID const& id_, const SourceInfo& source_, Environment& env_) : id(id_), name(id), state(State::initial), source(source_), - fileSource(fileSource_), + env(env_), debugBucket(debugFontBuffer) { // Initialize tile debug coordinates debugFontBuffer.addText(name.c_str(), 50, 200, 5); @@ -23,7 +24,7 @@ TileData::TileData(Tile::ID const& id_, const SourceInfo& source_, FileSource& f TileData::~TileData() { if (req) { - fileSource.cancel(req); + env.cancelRequest(req); } } @@ -31,8 +32,7 @@ const std::string TileData::toString() const { return std::string { "[tile " } + name + "]"; } -void TileData::request(uv::worker &worker, uv_loop_t &loop, - float pixelRatio, std::function<void()> callback) { +void TileData::request(uv::worker &worker, float pixelRatio, std::function<void()> callback) { if (source.tiles.empty()) return; @@ -53,9 +53,8 @@ void TileData::request(uv::worker &worker, uv_loop_t &loop, state = State::loading; - // Note: Somehow this feels slower than the change to request_http() std::weak_ptr<TileData> weak_tile = shared_from_this(); - req = fileSource.request({ Resource::Kind::Tile, url }, &loop, [weak_tile, url, callback, &worker](const Response &res) { + req = env.request({ Resource::Kind::Tile, url }, [weak_tile, url, callback, &worker](const Response &res) { util::ptr<TileData> tile = weak_tile.lock(); if (!tile || tile->state == State::obsolete) { // noop. Tile is obsolete and we're now just waiting for the refcount @@ -84,7 +83,7 @@ void TileData::cancel() { state = State::obsolete; } if (req) { - fileSource.cancel(req); + env.cancelRequest(req); req = nullptr; } } diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp index fcd741a1f8..66c0fbba2e 100644 --- a/src/mbgl/map/tile_data.hpp +++ b/src/mbgl/map/tile_data.hpp @@ -23,7 +23,7 @@ typedef struct uv_loop_s uv_loop_t; namespace mbgl { class Map; -class FileSource; +class Environment; class Painter; class SourceInfo; class StyleLayer; @@ -48,10 +48,10 @@ public: }; public: - TileData(Tile::ID const& id, const SourceInfo&, FileSource&); + TileData(Tile::ID const &id, const SourceInfo &, Environment &); ~TileData(); - void request(uv::worker&, uv_loop_t&, float pixelRatio, std::function<void ()> callback); + void request(uv::worker&, float pixelRatio, std::function<void ()> callback); void reparse(uv::worker&, std::function<void ()> callback); void cancel(); const std::string toString() const; @@ -72,7 +72,7 @@ public: public: const SourceInfo& source; - FileSource& fileSource; + Environment &env; protected: Request *req = nullptr; diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 68974aadf4..66fed0706b 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -14,8 +14,8 @@ VectorTileData::VectorTileData(Tile::ID const& id_, float mapMaxZoom, util::ptr<Style> style_, GlyphAtlas& glyphAtlas_, GlyphStore& glyphStore_, SpriteAtlas& spriteAtlas_, util::ptr<Sprite> sprite_, - const SourceInfo& source_, FileSource &fileSource_) - : TileData(id_, source_, fileSource_), + const SourceInfo& source_, Environment &env_) + : TileData(id_, source_, env_), glyphAtlas(glyphAtlas_), glyphStore(glyphStore_), spriteAtlas(spriteAtlas_), diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/map/vector_tile_data.hpp index feb3c6238b..1c48fc5f23 100644 --- a/src/mbgl/map/vector_tile_data.hpp +++ b/src/mbgl/map/vector_tile_data.hpp @@ -30,11 +30,8 @@ class VectorTileData : public TileData { friend class TileParser; public: - VectorTileData(Tile::ID const&, - float mapMaxZoom, util::ptr<Style>, - GlyphAtlas&, GlyphStore&, - SpriteAtlas&, util::ptr<Sprite>, - const SourceInfo&, FileSource &); + VectorTileData(Tile::ID const &, float mapMaxZoom, util::ptr<Style>, GlyphAtlas &, GlyphStore &, + SpriteAtlas &, util::ptr<Sprite>, const SourceInfo &, Environment &); ~VectorTileData(); void parse() override; diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp index c6b201b559..9f70ac9943 100644 --- a/src/mbgl/storage/default_file_source.cpp +++ b/src/mbgl/storage/default_file_source.cpp @@ -50,6 +50,10 @@ struct DefaultFileSource::ResultAction { struct DefaultFileSource::StopAction { }; +struct DefaultFileSource::AbortAction { + const Environment &env; +}; + DefaultFileSource::DefaultFileSource(FileCache *cache_, const std::string &root) : assetRoot(root.empty() ? platform::assetRoot() : root), @@ -105,8 +109,9 @@ SharedRequestBase *DefaultFileSource::find(const Resource &resource) { return nullptr; } -Request *DefaultFileSource::request(const Resource &resource, uv_loop_t *l, Callback callback) { - auto req = new Request(resource, l, std::move(callback)); +Request *DefaultFileSource::request(const Resource &resource, uv_loop_t *l, const Environment &env, + Callback callback) { + auto req = new Request(resource, l, env, std::move(callback)); // This function can be called from any thread. Make sure we're executing the actual call in the // file source loop by sending it over the queue. It will be processed in processAction(). @@ -114,8 +119,9 @@ Request *DefaultFileSource::request(const Resource &resource, uv_loop_t *l, Call return req; } -void DefaultFileSource::request(const Resource &resource, Callback callback) { - auto req = new Request(resource, nullptr, std::move(callback)); +void DefaultFileSource::request(const Resource &resource, const Environment &env, + Callback callback) { + auto req = new Request(resource, nullptr, env, std::move(callback)); // This function can be called from any thread. Make sure we're executing the actual call in the // file source loop by sending it over the queue. It will be processed in processAction(). @@ -130,6 +136,11 @@ void DefaultFileSource::cancel(Request *req) { queue->send(RemoveRequestAction{ req }); } +void DefaultFileSource::abort(const Environment &env) { + queue->send(AbortAction{ env }); +} + + void DefaultFileSource::process(AddRequestAction &action) { const Resource &resource = action.request->resource; @@ -209,18 +220,45 @@ void DefaultFileSource::process(ResultAction &action) { } } +// A stop action means the file source is about to be destructed. We need to cancel all requests +// for all environments. void DefaultFileSource::process(StopAction &) { - // Cancel all remaining requests. - for (auto it : pending) { - it.second->unsubscribeAll(); - } - pending.clear(); - + // There may not be any pending requests in this file source anymore. You must terminate all + // Map objects before deleting the FileSource. + assert(pending.empty()); assert(queue); queue->stop(); queue = nullptr; } +// Aborts all requests that are part of the current environment. +void DefaultFileSource::process(AbortAction &action) { + // Construct a cancellation response. + auto res = util::make_unique<Response>(); + res->status = Response::Error; + res->message = "Environment is terminating"; + std::shared_ptr<const Response> response = std::move(res); + + // Iterate through all pending requests and remove them in case they're abandoned. + util::erase_if(pending, [&](const std::pair<Resource, SharedRequestBase *> &it) -> bool { + // Obtain all pending requests that are in the current environment. + const auto aborted = it.second->removeAllInEnvironment(action.env); + + // Notify all observers. + for (auto req : aborted) { + req->notify(response); + } + + // Finally, remove all requests that are now abandoned. + if (it.second->abandoned()) { + it.second->cancel(); + return true; + } else { + return false; + } + }); +} + void DefaultFileSource::notify(SharedRequestBase *sharedRequest, const std::set<Request *> &observers, std::shared_ptr<const Response> response, FileCache::Hint hint) { @@ -235,8 +273,8 @@ void DefaultFileSource::notify(SharedRequestBase *sharedRequest, } // Notify all observers. - for (auto it : observers) { - it->notify(response); + for (auto req : observers) { + req->notify(response); } } diff --git a/src/mbgl/storage/request.cpp b/src/mbgl/storage/request.cpp index de18138ec2..48b5b774d2 100644 --- a/src/mbgl/storage/request.cpp +++ b/src/mbgl/storage/request.cpp @@ -13,8 +13,8 @@ namespace mbgl { // 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_) - : callback(callback_), resource(resource_) { +Request::Request(const Resource &resource_, uv_loop_t *loop, const Environment &env_, Callback callback_) + : callback(callback_), resource(resource_), env(env_) { // When there is no loop supplied (== nullptr), the callback will be fired in an arbitrary // thread (the thread notify() is called from) rather than kicking back to the calling thread. if (loop) { diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp index f89f42e909..ab1776c04b 100644 --- a/src/mbgl/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp @@ -1,5 +1,6 @@ #include <mbgl/text/glyph_store.hpp> +#include <mbgl/map/environment.hpp> #include <mbgl/util/std.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/utf.hpp> @@ -137,9 +138,11 @@ void FontStack::lineWrap(Shaping &shaping, const float lineHeight, const float m align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line); } -GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, FileSource& fileSource) - : future(promise.get_future().share()) -{ +GlyphPBF::GlyphPBF(const std::string &glyphURL, + const std::string &fontStack, + GlyphRange glyphRange, + Environment &env) + : future(promise.get_future().share()) { // Load the glyph set URL std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string { if (name == "fontstack") return util::percentEncode(fontStack); @@ -148,7 +151,7 @@ GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, Gl }); // The prepare call jumps back to the main thread. - fileSource.request({ Resource::Kind::Glyphs, url }, [&, url](const Response &res) { + env.requestAsync({ Resource::Kind::Glyphs, url }, [&, url](const Response &res) { if (res.status != Response::Successful) { // Something went wrong with loading the glyph pbf. Pass on the error to the future listeners. const std::string msg = std::string { "[ERROR] failed to load glyphs: " } + res.message; @@ -223,7 +226,7 @@ void GlyphPBF::parse(FontStack &stack) { data.clear(); } -GlyphStore::GlyphStore(FileSource& fileSource_) : fileSource(fileSource_), mtx(util::make_unique<uv::mutex>()) {} +GlyphStore::GlyphStore(Environment& env_) : env(env_), mtx(util::make_unique<uv::mutex>()) {} void GlyphStore::setURL(const std::string &url) { glyphURL = url; @@ -265,7 +268,7 @@ std::shared_future<GlyphPBF &> GlyphStore::loadGlyphRange(const std::string &fon auto range_it = rangeSets.find(range); if (range_it == rangeSets.end()) { // We don't have this glyph set yet for this font stack. - range_it = rangeSets.emplace(range, util::make_unique<GlyphPBF>(glyphURL, fontStack, range, fileSource)).first; + range_it = rangeSets.emplace(range, util::make_unique<GlyphPBF>(glyphURL, fontStack, range, env)).first; } return range_it->second->getFuture(); diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp index 6839045d61..406234241d 100644 --- a/src/mbgl/text/glyph_store.hpp +++ b/src/mbgl/text/glyph_store.hpp @@ -17,6 +17,7 @@ namespace mbgl { class FileSource; +class Environment; class SDFGlyph { public: @@ -49,7 +50,10 @@ private: class GlyphPBF { public: - GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, FileSource& fileSource); + GlyphPBF(const std::string &glyphURL, + const std::string &fontStack, + GlyphRange glyphRange, + Environment &env); private: GlyphPBF(const GlyphPBF &) = delete; @@ -72,7 +76,7 @@ private: // Manages Glyphrange PBF loading. class GlyphStore { public: - GlyphStore(FileSource& fileSource); + GlyphStore(Environment &); // Block until all specified GlyphRanges of the specified font stack are loaded. void waitForGlyphRanges(const std::string &fontStack, const std::set<GlyphRange> &glyphRanges); @@ -88,7 +92,7 @@ private: FontStack &createFontStack(const std::string &fontStack); std::string glyphURL; - FileSource& fileSource; + Environment &env; std::unordered_map<std::string, std::map<GlyphRange, std::unique_ptr<GlyphPBF>>> ranges; std::unordered_map<std::string, std::unique_ptr<FontStack>> stacks; std::unique_ptr<uv::mutex> mtx; |