diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2015-11-05 14:54:50 -0800 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2015-11-12 13:03:14 -0800 |
commit | f9ebe54a6336431af98ebfb428d28a0513b2522d (patch) | |
tree | 83c01deae617e3e40bc0e47c32a36d6d24f7a23a | |
parent | 1e350b7ea485117cadc413d4d41062cf3c3c43a1 (diff) | |
download | qtlocation-mapboxgl-f9ebe54a6336431af98ebfb428d28a0513b2522d.tar.gz |
[core] Merge Sprite into SpriteStore
-rw-r--r-- | src/mbgl/layer/symbol_layer.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/map_context.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/tile_worker.cpp | 5 | ||||
-rw-r--r-- | src/mbgl/renderer/symbol_bucket.cpp | 7 | ||||
-rw-r--r-- | src/mbgl/renderer/symbol_bucket.hpp | 5 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite.cpp | 119 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite.hpp | 57 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite_atlas.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite_store.cpp | 115 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite_store.hpp | 41 | ||||
-rw-r--r-- | src/mbgl/style/style.cpp | 26 | ||||
-rw-r--r-- | src/mbgl/style/style.hpp | 14 | ||||
-rw-r--r-- | src/mbgl/style/style_bucket_parameters.hpp | 8 | ||||
-rw-r--r-- | src/mbgl/style/style_parser.cpp | 22 | ||||
-rw-r--r-- | src/mbgl/style/style_parser.hpp | 15 | ||||
-rw-r--r-- | test/sprite/sprite.cpp | 173 | ||||
-rw-r--r-- | test/sprite/sprite_atlas.cpp | 6 | ||||
-rw-r--r-- | test/sprite/sprite_store.cpp | 179 | ||||
-rw-r--r-- | test/test.gypi | 1 |
19 files changed, 364 insertions, 436 deletions
diff --git a/src/mbgl/layer/symbol_layer.cpp b/src/mbgl/layer/symbol_layer.cpp index 4ba18f4e6c..8e43d3454e 100644 --- a/src/mbgl/layer/symbol_layer.cpp +++ b/src/mbgl/layer/symbol_layer.cpp @@ -168,7 +168,7 @@ std::unique_ptr<Bucket> SymbolLayer::createBucket(StyleBucketParameters& paramet bucket->parseFeatures(parameters.layer, filter); - if (bucket->needsDependencies(parameters.glyphStore, parameters.sprite)) { + if (bucket->needsDependencies(parameters.glyphStore, parameters.spriteStore)) { parameters.partialParse = true; } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index dedfff02d8..031fbb57ca 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -169,7 +169,7 @@ void MapContext::update() { data.setAnimationTime(Clock::now()); - if (style->sprite && updateFlags & Update::Annotations) { + if (updateFlags & Update::Annotations) { data.getAnnotationManager()->updateStyle(*style); updateFlags |= Update::Classes; } diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index effb90a73d..9dc0698db7 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -21,7 +21,6 @@ TileWorker::TileWorker(TileID id_, sourceID(sourceID_), style(style_), state(state_) { - assert(style.sprite); } TileWorker::~TileWorker() { @@ -64,7 +63,7 @@ TileParseResult TileWorker::parsePendingLayers() { if (layer.type == StyleLayerType::Symbol) { auto symbolBucket = dynamic_cast<SymbolBucket*>(bucket.get()); - if (!symbolBucket->needsDependencies(*style.glyphStore, *style.sprite)) { + if (!symbolBucket->needsDependencies(*style.glyphStore, *style.spriteStore)) { symbolBucket->addFeatures(reinterpret_cast<uintptr_t>(this), *style.spriteAtlas, *style.glyphAtlas, *style.glyphStore, *collisionTile); insertBucket(layer.bucketName(), std::move(bucket)); @@ -130,7 +129,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr reinterpret_cast<uintptr_t>(this), partialParse, *style.spriteAtlas, - *style.sprite, + *style.spriteStore, *style.glyphAtlas, *style.glyphStore, *collisionTile); diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index 1071fdcce9..1f2ad96bf2 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -1,8 +1,8 @@ #include <mbgl/renderer/symbol_bucket.hpp> #include <mbgl/layer/symbol_layer.hpp> #include <mbgl/map/geometry_tile.hpp> -#include <mbgl/sprite/sprite.hpp> #include <mbgl/sprite/sprite_image.hpp> +#include <mbgl/sprite/sprite_store.hpp> #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/geometry/text_buffer.hpp> #include <mbgl/geometry/icon_buffer.hpp> @@ -158,13 +158,12 @@ void SymbolBucket::parseFeatures(const GeometryTileLayer& layer, } } -bool SymbolBucket::needsDependencies(GlyphStore& glyphStore, - Sprite& sprite) { +bool SymbolBucket::needsDependencies(GlyphStore& glyphStore, SpriteStore& spriteStore) { if (!layout.text.field.value.empty() && !layout.text.font.value.empty() && !glyphStore.hasGlyphRanges(layout.text.font, ranges)) { return true; } - if (!layout.icon.image.value.empty() && !sprite.isLoaded()) { + if (!layout.icon.image.value.empty() && !spriteStore.isLoaded()) { return true; } diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp index 3c6f5f6d25..ff4bbf5dca 100644 --- a/src/mbgl/renderer/symbol_bucket.hpp +++ b/src/mbgl/renderer/symbol_bucket.hpp @@ -28,7 +28,7 @@ class CollisionBoxShader; class DotShader; class CollisionTile; class SpriteAtlas; -class Sprite; +class SpriteStore; class GlyphAtlas; class GlyphStore; @@ -88,8 +88,7 @@ public: void parseFeatures(const GeometryTileLayer&, const FilterExpression&); - bool needsDependencies(GlyphStore& glyphStore, - Sprite& sprite); + bool needsDependencies(GlyphStore&, SpriteStore&); void placeFeatures(CollisionTile&) override; private: diff --git a/src/mbgl/sprite/sprite.cpp b/src/mbgl/sprite/sprite.cpp deleted file mode 100644 index 881a6ff8ed..0000000000 --- a/src/mbgl/sprite/sprite.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include <mbgl/sprite/sprite.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/platform/platform.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/storage/resource.hpp> -#include <mbgl/storage/response.hpp> -#include <mbgl/storage/request_holder.hpp> -#include <mbgl/util/exception.hpp> -#include <mbgl/util/raster.hpp> -#include <mbgl/util/thread.hpp> -#include <mbgl/util/uv_detail.hpp> -#include <mbgl/util/mapbox.hpp> - -#include <rapidjson/document.h> - -#include <string> -#include <sstream> - -namespace mbgl { - -struct Sprite::Loader { - std::shared_ptr<const std::string> image; - std::shared_ptr<const std::string> json; - RequestHolder jsonRequest; - RequestHolder spriteRequest; -}; - -Sprite::Sprite(const std::string& baseUrl, float pixelRatio_) - : pixelRatio(pixelRatio_ > 1 ? 2 : 1) { - if (baseUrl.empty()) { - // Treat a non-existent sprite as a successfully loaded empty sprite. - loaded = true; - return; - } - - std::string spriteURL(baseUrl + (pixelRatio_ > 1 ? "@2x" : "") + ".png"); - std::string jsonURL(baseUrl + (pixelRatio_ > 1 ? "@2x" : "") + ".json"); - - loader = std::make_unique<Loader>(); - - FileSource* fs = util::ThreadContext::getFileSource(); - loader->jsonRequest = fs->request({ Resource::Kind::SpriteJSON, jsonURL }, util::RunLoop::getLoop(), - [this, jsonURL](const Response& res) { - if (res.stale) { - // Only handle fresh responses. - return; - } - loader->jsonRequest = nullptr; - - if (res.error) { - std::stringstream message; - message << "Failed to load [" << jsonURL << "]: " << res.error->message; - emitSpriteLoadingFailed(message.str()); - return; - } else { - loader->json = res.data; - } - emitSpriteLoadedIfComplete(); - }); - - loader->spriteRequest = - fs->request({ Resource::Kind::SpriteImage, spriteURL }, util::RunLoop::getLoop(), - [this, spriteURL](const Response& res) { - if (res.stale) { - // Only handle fresh responses. - return; - } - loader->spriteRequest = nullptr; - - if (res.error) { - std::stringstream message; - message << "Failed to load [" << spriteURL << "]: " << res.error->message; - emitSpriteLoadingFailed(message.str()); - return; - } else { - loader->image = res.data; - } - emitSpriteLoadedIfComplete(); - }); -} - -Sprite::~Sprite() { -} - -void Sprite::emitSpriteLoadedIfComplete() { - assert(loader); - - if (!loader->image || !loader->json || !observer) { - return; - } - - auto local = std::move(loader); - auto result = parseSprite(*local->image, *local->json); - if (result.is<Sprites>()) { - loaded = true; - observer->onSpriteLoaded(result.get<Sprites>()); - } else { - emitSpriteLoadingFailed(result.get<std::string>()); - } -} - -void Sprite::emitSpriteLoadingFailed(const std::string& message) { - if (!observer) { - return; - } - - auto error = std::make_exception_ptr(util::SpriteLoadingException(message)); - observer->onSpriteLoadingFailed(error); -} - -void Sprite::setObserver(Observer* observer_) { - observer = observer_; -} - -void Sprite::dumpDebugLogs() const { - Log::Info(Event::General, "Sprite::loaded: %d", loaded); -} - -} // namespace mbgl diff --git a/src/mbgl/sprite/sprite.hpp b/src/mbgl/sprite/sprite.hpp deleted file mode 100644 index d204b42e85..0000000000 --- a/src/mbgl/sprite/sprite.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef MBGL_SPRITE -#define MBGL_SPRITE - -#include <mbgl/sprite/sprite_parser.hpp> -#include <mbgl/util/image.hpp> -#include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/ptr.hpp> -#include <mbgl/storage/request.hpp> - -#include <cstdint> -#include <atomic> -#include <iosfwd> -#include <string> -#include <unordered_map> - -namespace mbgl { - -class Request; - -class Sprite : private util::noncopyable { -public: - class Observer { - public: - virtual ~Observer() = default; - - virtual void onSpriteLoaded(const Sprites& sprites) = 0; - virtual void onSpriteLoadingFailed(std::exception_ptr error) = 0; - }; - - Sprite(const std::string& baseUrl, float pixelRatio); - ~Sprite(); - - inline bool isLoaded() const { - return loaded; - } - - void dumpDebugLogs() const; - - const float pixelRatio; - - void setObserver(Observer* observer); - -private: - void emitSpriteLoadedIfComplete(); - void emitSpriteLoadingFailed(const std::string& message); - - struct Loader; - std::unique_ptr<Loader> loader; - - bool loaded = false; - - Observer* observer = nullptr; -}; - -} // namespace mbgl - -#endif diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp index 22c2ba8b95..45b0511c68 100644 --- a/src/mbgl/sprite/sprite_atlas.cpp +++ b/src/mbgl/sprite/sprite_atlas.cpp @@ -10,13 +10,10 @@ #include <mbgl/util/scaling.hpp> #include <mbgl/util/thread_context.hpp> -#include <mbgl/sprite/sprite.hpp> - #include <cassert> #include <cmath> #include <algorithm> - using namespace mbgl; SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_, SpriteStore& store_) diff --git a/src/mbgl/sprite/sprite_store.cpp b/src/mbgl/sprite/sprite_store.cpp index fb6833114e..27b33e51e3 100644 --- a/src/mbgl/sprite/sprite_store.cpp +++ b/src/mbgl/sprite/sprite_store.cpp @@ -1,9 +1,122 @@ #include <mbgl/sprite/sprite_store.hpp> - +#include <mbgl/sprite/sprite_parser.hpp> #include <mbgl/platform/log.hpp> +#include <mbgl/storage/file_source.hpp> +#include <mbgl/storage/resource.hpp> +#include <mbgl/storage/response.hpp> +#include <mbgl/storage/request_holder.hpp> +#include <mbgl/util/exception.hpp> +#include <mbgl/util/thread_context.hpp> +#include <mbgl/util/run_loop.hpp> + +#include <string> +#include <sstream> namespace mbgl { +struct SpriteStore::Loader { + std::shared_ptr<const std::string> image; + std::shared_ptr<const std::string> json; + RequestHolder jsonRequest; + RequestHolder spriteRequest; +}; + +SpriteStore::SpriteStore(float pixelRatio_) + : pixelRatio(pixelRatio_ > 1 ? 2 : 1) { +} + +SpriteStore::~SpriteStore() = default; + +void SpriteStore::setURL(const std::string& url) { + if (url.empty()) { + // Treat a non-existent sprite as a successfully loaded empty sprite. + loaded = true; + return; + } + + std::string spriteURL(url + (pixelRatio > 1 ? "@2x" : "") + ".png"); + std::string jsonURL(url + (pixelRatio > 1 ? "@2x" : "") + ".json"); + + loader = std::make_unique<Loader>(); + + FileSource* fs = util::ThreadContext::getFileSource(); + loader->jsonRequest = fs->request({ Resource::Kind::SpriteJSON, jsonURL }, util::RunLoop::getLoop(), + [this, jsonURL](const Response& res) { + if (res.stale) { + // Only handle fresh responses. + return; + } + loader->jsonRequest = nullptr; + + if (res.error) { + std::stringstream message; + message << "Failed to load [" << jsonURL << "]: " << res.error->message; + emitSpriteLoadingFailed(message.str()); + return; + } else { + loader->json = res.data; + } + emitSpriteLoadedIfComplete(); + }); + + loader->spriteRequest = + fs->request({ Resource::Kind::SpriteImage, spriteURL }, util::RunLoop::getLoop(), + [this, spriteURL](const Response& res) { + if (res.stale) { + // Only handle fresh responses. + return; + } + loader->spriteRequest = nullptr; + + if (res.error) { + std::stringstream message; + message << "Failed to load [" << spriteURL << "]: " << res.error->message; + emitSpriteLoadingFailed(message.str()); + return; + } else { + loader->image = res.data; + } + emitSpriteLoadedIfComplete(); + }); +} + +void SpriteStore::emitSpriteLoadedIfComplete() { + assert(loader); + + if (!loader->image || !loader->json) { + return; + } + + auto local = std::move(loader); + auto result = parseSprite(*local->image, *local->json); + if (result.is<Sprites>()) { + loaded = true; + setSprites(result.get<Sprites>()); + if (observer) { + observer->onSpriteLoaded(); + } + } else { + emitSpriteLoadingFailed(result.get<std::string>()); + } +} + +void SpriteStore::emitSpriteLoadingFailed(const std::string& message) { + if (!observer) { + return; + } + + auto error = std::make_exception_ptr(util::SpriteLoadingException(message)); + observer->onSpriteLoadingFailed(error); +} + +void SpriteStore::setObserver(Observer* observer_) { + observer = observer_; +} + +void SpriteStore::dumpDebugLogs() const { + Log::Info(Event::General, "SpriteStore::loaded: %d", loaded); +} + void SpriteStore::setSprite(const std::string& name, std::shared_ptr<const SpriteImage> sprite) { std::lock_guard<std::mutex> lock(mutex); _setSprite(name, sprite); diff --git a/src/mbgl/sprite/sprite_store.hpp b/src/mbgl/sprite/sprite_store.hpp index ed903f074b..98b43ac8e4 100644 --- a/src/mbgl/sprite/sprite_store.hpp +++ b/src/mbgl/sprite/sprite_store.hpp @@ -2,24 +2,39 @@ #define MBGL_SPRITE_STORE #include <mbgl/sprite/sprite_image.hpp> - #include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/geo.hpp> #include <map> -#include <set> -#include <vector> #include <memory> #include <mutex> -#include <cstdint> namespace mbgl { -// The SpriteStore object holds Sprite images. class SpriteStore : private util::noncopyable { +public: using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; -public: + class Observer { + public: + virtual ~Observer() = default; + + virtual void onSpriteLoaded() = 0; + virtual void onSpriteLoadingFailed(std::exception_ptr) = 0; + }; + + SpriteStore(float pixelRatio); + ~SpriteStore(); + + void setURL(const std::string&); + + bool isLoaded() const { + return loaded; + } + + void dumpDebugLogs() const; + + void setObserver(Observer* observer); + // Adds/replaces a Sprite image. void setSprite(const std::string&, std::shared_ptr<const SpriteImage> = nullptr); @@ -35,9 +50,21 @@ public: // Returns Sprite images that changed since the last invocation of this function. Sprites getDirty(); + const float pixelRatio; + private: void _setSprite(const std::string&, const std::shared_ptr<const SpriteImage>& = nullptr); + void emitSpriteLoadedIfComplete(); + void emitSpriteLoadingFailed(const std::string& message); + + struct Loader; + std::unique_ptr<Loader> loader; + + bool loaded = false; + + Observer* observer = nullptr; + // Lock for sprites and dirty maps. std::mutex mutex; diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index acf4752e07..14d93fb12a 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -2,7 +2,6 @@ #include <mbgl/map/map_data.hpp> #include <mbgl/map/source.hpp> #include <mbgl/map/transform_state.hpp> -#include <mbgl/sprite/sprite.hpp> #include <mbgl/sprite/sprite_store.hpp> #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/style/style_layer.hpp> @@ -28,12 +27,13 @@ Style::Style(MapData& data_) : data(data_), glyphStore(std::make_unique<GlyphStore>()), glyphAtlas(std::make_unique<GlyphAtlas>(1024, 1024)), - spriteStore(std::make_unique<SpriteStore>()), + spriteStore(std::make_unique<SpriteStore>(data.pixelRatio)), spriteAtlas(std::make_unique<SpriteAtlas>(512, 512, data.pixelRatio, *spriteStore)), lineAtlas(std::make_unique<LineAtlas>(512, 512)), mtx(std::make_unique<uv::rwlock>()), workers(4) { glyphStore->setObserver(this); + spriteStore->setObserver(this); } void Style::setJSON(const std::string& json, const std::string&) { @@ -55,10 +55,8 @@ void Style::setJSON(const std::string& json, const std::string&) { addLayer(std::move(layer)); } - sprite = std::make_unique<Sprite>(parser.getSprite(), data.pixelRatio); - sprite->setObserver(this); - glyphStore->setURL(parser.getGlyphURL()); + spriteStore->setURL(parser.getSpriteURL()); } Style::~Style() { @@ -67,10 +65,7 @@ Style::~Style() { } glyphStore->setObserver(nullptr); - - if (sprite) { - sprite->setObserver(nullptr); - } + spriteStore->setObserver(nullptr); } void Style::addSource(std::unique_ptr<Source> source) { @@ -186,7 +181,7 @@ bool Style::isLoaded() const { } } - if (sprite && !sprite->isLoaded()) { + if (!spriteStore->isLoaded()) { return false; } @@ -230,10 +225,7 @@ void Style::onTileLoadingFailed(std::exception_ptr error) { emitResourceLoadingFailed(error); } -void Style::onSpriteLoaded(const Sprites& sprites) { - // Add all sprite images to the SpriteStore object - spriteStore->setSprites(sprites); - +void Style::onSpriteLoaded() { shouldReparsePartialTiles = true; emitTileDataChanged(); } @@ -272,11 +264,7 @@ void Style::dumpDebugLogs() const { source->dumpDebugLogs(); } - if (!sprite) { - Log::Info(Event::General, "no sprite loaded"); - } else { - sprite->dumpDebugLogs(); - } + spriteStore->dumpDebugLogs(); } } diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index 837703e264..5f18a8fec4 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -5,10 +5,9 @@ #include <mbgl/style/zoom_history.hpp> #include <mbgl/map/source.hpp> -#include <mbgl/sprite/sprite.hpp> #include <mbgl/text/glyph_store.hpp> +#include <mbgl/sprite/sprite_store.hpp> -#include <mbgl/util/ptr.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/chrono.hpp> #include <mbgl/util/worker.hpp> @@ -27,8 +26,8 @@ class LineAtlas; class StyleLayer; class Style : public GlyphStore::Observer, + public SpriteStore::Observer, public Source::Observer, - public Sprite::Observer, public util::noncopyable { public: Style(MapData&); @@ -74,7 +73,6 @@ public: MapData& data; std::unique_ptr<GlyphStore> glyphStore; std::unique_ptr<GlyphAtlas> glyphAtlas; - util::ptr<Sprite> sprite; std::unique_ptr<SpriteStore> spriteStore; std::unique_ptr<SpriteAtlas> spriteAtlas; std::unique_ptr<LineAtlas> lineAtlas; @@ -89,16 +87,16 @@ private: void onGlyphRangeLoaded() override; void onGlyphRangeLoadingFailed(std::exception_ptr error) override; + // SpriteStore::Observer implementation. + void onSpriteLoaded() override; + void onSpriteLoadingFailed(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(const Sprites& sprites) override; - void onSpriteLoadingFailed(std::exception_ptr error) override; - void emitTileDataChanged(); void emitResourceLoadingFailed(std::exception_ptr error); diff --git a/src/mbgl/style/style_bucket_parameters.hpp b/src/mbgl/style/style_bucket_parameters.hpp index 8328e254ca..c27d1287b2 100644 --- a/src/mbgl/style/style_bucket_parameters.hpp +++ b/src/mbgl/style/style_bucket_parameters.hpp @@ -12,7 +12,7 @@ class TileID; class GeometryTileLayer; class GeometryTileFeature; class SpriteAtlas; -class Sprite; +class SpriteStore; class GlyphAtlas; class GlyphStore; class CollisionTile; @@ -25,7 +25,7 @@ public: uintptr_t tileUID_, bool& partialParse_, SpriteAtlas& spriteAtlas_, - Sprite& sprite_, + SpriteStore& spriteStore_, GlyphAtlas& glyphAtlas_, GlyphStore& glyphStore_, CollisionTile& collisionTile_) @@ -35,7 +35,7 @@ public: tileUID(tileUID_), partialParse(partialParse_), spriteAtlas(spriteAtlas_), - sprite(sprite_), + spriteStore(spriteStore_), glyphAtlas(glyphAtlas_), glyphStore(glyphStore_), collisionTile(collisionTile_) {} @@ -52,7 +52,7 @@ public: uintptr_t tileUID; bool& partialParse; SpriteAtlas& spriteAtlas; - Sprite& sprite; + SpriteStore& spriteStore; GlyphAtlas& glyphAtlas; GlyphStore& glyphStore; CollisionTile& collisionTile; diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index 41dbb74b38..dc14827dc6 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -24,11 +24,17 @@ void StyleParser::parse(const JSVal& document) { } if (document.HasMember("sprite")) { - parseSprite(document["sprite"]); + const JSVal& sprite = document["sprite"]; + if (sprite.IsString()) { + spriteURL = { sprite.GetString(), sprite.GetStringLength() }; + } } if (document.HasMember("glyphs")) { - parseGlyphURL(document["glyphs"]); + const JSVal& glyphs = document["glyphs"]; + if (glyphs.IsString()) { + glyphURL = { glyphs.GetString(), glyphs.GetStringLength() }; + } } } @@ -266,18 +272,6 @@ void StyleParser::parseLayer(const std::string& id, const JSVal& value, util::pt layer->parsePaints(value); } -void StyleParser::parseSprite(const JSVal& value) { - if (value.IsString()) { - sprite = { value.GetString(), value.GetStringLength() }; - } -} - -void StyleParser::parseGlyphURL(const JSVal& value) { - if (value.IsString()) { - glyph_url = { value.GetString(), value.GetStringLength() }; - } -} - void StyleParser::parseVisibility(StyleLayer& layer, const JSVal& value) { if (!value.HasMember("visibility")) { return; diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp index 1b2ae183d4..489c9959f2 100644 --- a/src/mbgl/style/style_parser.hpp +++ b/src/mbgl/style/style_parser.hpp @@ -31,20 +31,18 @@ public: return layers; } - std::string getSprite() const { - return sprite; + std::string getSpriteURL() const { + return spriteURL; } std::string getGlyphURL() const { - return glyph_url; + return glyphURL; } private: void parseSources(const JSVal&); void parseLayers(const JSVal&); void parseLayer(const std::string& id, const JSVal&, util::ptr<StyleLayer>&); - void parseSprite(const JSVal&); - void parseGlyphURL(const JSVal&); void parseVisibility(StyleLayer&, const JSVal& value); std::uint8_t version; @@ -58,11 +56,8 @@ private: // Store a stack of layer IDs we're parsing right now. This is to prevent reference cycles. std::forward_list<std::string> stack; - // Base URL of the sprite image. - std::string sprite; - - // URL template for glyph PBFs. - std::string glyph_url; + std::string spriteURL; + std::string glyphURL; }; } diff --git a/test/sprite/sprite.cpp b/test/sprite/sprite.cpp deleted file mode 100644 index 7575cb3c9a..0000000000 --- a/test/sprite/sprite.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include "../fixtures/fixture_log_observer.hpp" -#include "../fixtures/mock_file_source.hpp" -#include "../fixtures/util.hpp" - -#include <mbgl/sprite/sprite.hpp> -#include <mbgl/util/run_loop.hpp> -#include <mbgl/util/thread.hpp> - -using namespace mbgl; - -using SpriteTestCallback = std::function<void(Sprite*, const Sprites&, std::exception_ptr)>; - -struct SpriteParams { - const std::string baseUrl; - const float pixelRatio; -}; - -class SpriteThread : public Sprite::Observer { -public: - SpriteThread(FileSource* fileSource, SpriteTestCallback callback) : callback_(callback) { - util::ThreadContext::setFileSource(fileSource); - } - - void loadSprite(const SpriteParams& params) { - sprite_.reset(new Sprite(params.baseUrl, params.pixelRatio)); - sprite_->setObserver(this); - } - - void unloadSprite() { - sprite_->setObserver(nullptr); - sprite_.reset(); - } - - void onSpriteLoaded(const Sprites& sprites) override { - callback_(sprite_.get(), sprites, nullptr); - } - - void onSpriteLoadingFailed(std::exception_ptr error) override { - callback_(sprite_.get(), Sprites(), error); - } - -private: - std::unique_ptr<Sprite> sprite_; - SpriteTestCallback callback_; -}; - -class SpriteTest : public testing::Test { -protected: - void runTest(const SpriteParams& params, FileSource* fileSource, SpriteTestCallback callback) { - util::RunLoop loop(uv_default_loop()); - - async_ = std::make_unique<uv::async>(loop.get(), [&] { loop.stop(); }); - async_->unref(); - - const util::ThreadContext context = {"Map", util::ThreadType::Map, util::ThreadPriority::Regular}; - - util::Thread<SpriteThread> tester(context, fileSource, callback); - tester.invoke(&SpriteThread::loadSprite, params); - - uv_run(loop.get(), UV_RUN_DEFAULT); - - tester.invoke(&SpriteThread::unloadSprite); - } - - void stopTest() { - async_->send(); - } - -private: - std::unique_ptr<uv::async> async_; -}; - -TEST_F(SpriteTest, LoadingSuccess) { - SpriteParams params = { - "test/fixtures/resources/sprite", - 1.0, - }; - - auto callback = [this, ¶ms](Sprite* sprite, const Sprites& sprites, std::exception_ptr error) { - ASSERT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Map)); - - ASSERT_TRUE(error == nullptr); - - ASSERT_TRUE(!sprites.empty()); - - ASSERT_EQ(sprite->pixelRatio, params.pixelRatio); - ASSERT_NE(sprite->pixelRatio, 1.5); - ASSERT_NE(sprite->pixelRatio, 2.0); - - ASSERT_TRUE(sprite->isLoaded()); - - stopTest(); - }; - - MockFileSource fileSource(MockFileSource::Success, ""); - runTest(params, &fileSource, callback); -} - -TEST_F(SpriteTest, LoadingFail) { - SpriteParams params = { - "test/fixtures/resources/sprite", - 1.0, - }; - - auto callback = [this, ¶ms](Sprite* sprite, const Sprites&, std::exception_ptr error) { - ASSERT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Map)); - - ASSERT_TRUE(error != nullptr); - - ASSERT_EQ(sprite->pixelRatio, params.pixelRatio); - ASSERT_NE(sprite->pixelRatio, 1.5); - ASSERT_NE(sprite->pixelRatio, 2.0); - - ASSERT_FALSE(sprite->isLoaded()); - - stopTest(); - }; - - MockFileSource fileSourceFailSpriteJSON(MockFileSource::RequestFail, "sprite.json"); - runTest(params, &fileSourceFailSpriteJSON, callback); - - MockFileSource fileSourceFailSpriteImage(MockFileSource::RequestFail, "sprite.png"); - runTest(params, &fileSourceFailSpriteImage, callback); - - MockFileSource fileSourceCorruptedSpriteJSON(MockFileSource::RequestWithCorruptedData, "sprite.json"); - runTest(params, &fileSourceCorruptedSpriteJSON, callback); - - MockFileSource fileSourceCorruptedSpriteImage(MockFileSource::RequestWithCorruptedData, "sprite.png"); - runTest(params, &fileSourceCorruptedSpriteImage, callback); -} - -TEST_F(SpriteTest, LoadingCancel) { - SpriteParams params = { - "test/fixtures/resources/sprite", - 1.0, - }; - - auto callback = [this](Sprite*, const Sprites&, std::exception_ptr) { - FAIL() << "Should never be called"; - }; - - MockFileSource fileSourceDelaySpriteJSON(MockFileSource::SuccessWithDelay, "sprite.json"); - fileSourceDelaySpriteJSON.setOnRequestDelayedCallback([this]{ - stopTest(); - }); - runTest(params, &fileSourceDelaySpriteJSON, callback); - - MockFileSource fileSourceDelaySpriteImage(MockFileSource::SuccessWithDelay, "sprite.png"); - fileSourceDelaySpriteImage.setOnRequestDelayedCallback([this]{ - stopTest(); - }); - runTest(params, &fileSourceDelaySpriteImage, callback); -} - -TEST_F(SpriteTest, InvalidURL) { - SpriteParams params = { - "foo bar", - 1.0, - }; - - auto callback = [this](Sprite* sprite, const Sprites&, std::exception_ptr error) { - ASSERT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Map)); - - ASSERT_TRUE(error != nullptr); - - ASSERT_EQ(sprite->isLoaded(), false); - - stopTest(); - }; - - MockFileSource fileSource(MockFileSource::Success, ""); - runTest(params, &fileSource, callback); -} diff --git a/test/sprite/sprite_atlas.cpp b/test/sprite/sprite_atlas.cpp index 554ef16da9..e54a88dabe 100644 --- a/test/sprite/sprite_atlas.cpp +++ b/test/sprite/sprite_atlas.cpp @@ -15,7 +15,7 @@ TEST(Sprite, SpriteAtlas) { auto spriteParseResult = parseSprite(util::read_file("test/fixtures/annotations/emerald.png"), util::read_file("test/fixtures/annotations/emerald.json")); - SpriteStore store; + SpriteStore store(1); store.setSprites(spriteParseResult.get<Sprites>()); SpriteAtlas atlas(63, 112, 1, store); @@ -90,7 +90,7 @@ TEST(Sprite, SpriteAtlasSize) { auto spriteParseResult = parseSprite(util::read_file("test/fixtures/annotations/emerald.png"), util::read_file("test/fixtures/annotations/emerald.json")); - SpriteStore store; + SpriteStore store(1); store.setSprites(spriteParseResult.get<Sprites>()); SpriteAtlas atlas(63, 112, 1.4, store); @@ -124,7 +124,7 @@ TEST(Sprite, SpriteAtlasSize) { } TEST(Sprite, SpriteAtlasUpdates) { - SpriteStore store; + SpriteStore store(1); SpriteAtlas atlas(32, 32, 1, store); diff --git a/test/sprite/sprite_store.cpp b/test/sprite/sprite_store.cpp index 17fce62a2b..14ea6c957b 100644 --- a/test/sprite/sprite_store.cpp +++ b/test/sprite/sprite_store.cpp @@ -1,8 +1,12 @@ #include "../fixtures/util.hpp" #include "../fixtures/fixture_log_observer.hpp" +#include "../fixtures/mock_file_source.hpp" #include <mbgl/sprite/sprite_store.hpp> +#include <mbgl/util/run_loop.hpp> +#include <mbgl/util/thread.hpp> + using namespace mbgl; TEST(Sprite, SpriteStore) { @@ -13,7 +17,7 @@ TEST(Sprite, SpriteStore) { const auto sprite3 = std::make_shared<SpriteImage>(8, 8, 2, std::string(16 * 16 * 4, '\0')); using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; - SpriteStore store; + SpriteStore store(1); // Adding single store.setSprite("one", sprite1); @@ -77,7 +81,7 @@ TEST(Sprite, SpriteStoreOtherPixelRatio) { const auto sprite1 = std::make_shared<SpriteImage>(8, 8, 1, std::string(8 * 8 * 4, '\0')); using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; - SpriteStore store; + SpriteStore store(1); // Adding mismatched sprite image store.setSprite("one", sprite1); @@ -89,7 +93,7 @@ TEST(Sprite, SpriteStoreMultiple) { const auto sprite2 = std::make_shared<SpriteImage>(8, 8, 2, std::string(16 * 16 * 4, '\0')); using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; - SpriteStore store; + SpriteStore store(1); store.setSprites({ { "one", sprite1 }, { "two", sprite2 }, @@ -108,7 +112,7 @@ TEST(Sprite, SpriteStoreReplace) { const auto sprite2 = std::make_shared<SpriteImage>(8, 8, 2, std::string(16 * 16 * 4, '\0')); using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; - SpriteStore store; + SpriteStore store(1); store.setSprite("sprite", sprite1); EXPECT_EQ(sprite1, store.getSprite("sprite")); @@ -125,7 +129,7 @@ TEST(Sprite, SpriteStoreReplaceWithDifferentDimensions) { const auto sprite2 = std::make_shared<SpriteImage>(9, 9, 2, std::string(18 * 18 * 4, '\0')); using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>; - SpriteStore store; + SpriteStore store(1); store.setSprite("sprite", sprite1); store.setSprite("sprite", sprite2); @@ -141,3 +145,168 @@ TEST(Sprite, SpriteStoreReplaceWithDifferentDimensions) { EXPECT_EQ(Sprites({ { "sprite", sprite1 } }), store.getDirty()); } + +using SpriteTestCallback = std::function<void(SpriteStore*, std::exception_ptr)>; + +struct SpriteParams { + const std::string baseUrl; + const float pixelRatio; +}; + +class SpriteThread : public SpriteStore::Observer { +public: + SpriteThread(FileSource* fileSource, SpriteTestCallback callback) : callback_(callback) { + util::ThreadContext::setFileSource(fileSource); + } + + void loadSprite(const SpriteParams& params) { + spriteStore_.reset(new SpriteStore(params.pixelRatio)); + spriteStore_->setObserver(this); + spriteStore_->setURL(params.baseUrl); + } + + void unloadSprite() { + spriteStore_->setObserver(nullptr); + spriteStore_.reset(); + } + + void onSpriteLoaded() override { + callback_(spriteStore_.get(), nullptr); + } + + void onSpriteLoadingFailed(std::exception_ptr error) override { + callback_(spriteStore_.get(), error); + } + +private: + std::unique_ptr<SpriteStore> spriteStore_; + SpriteTestCallback callback_; +}; + +class SpriteTest : public testing::Test { +protected: + void runTest(const SpriteParams& params, FileSource* fileSource, SpriteTestCallback callback) { + util::RunLoop loop(uv_default_loop()); + + async_ = std::make_unique<uv::async>(loop.get(), [&] { loop.stop(); }); + async_->unref(); + + const util::ThreadContext context = {"Map", util::ThreadType::Map, util::ThreadPriority::Regular}; + + util::Thread<SpriteThread> tester(context, fileSource, callback); + tester.invoke(&SpriteThread::loadSprite, params); + + uv_run(loop.get(), UV_RUN_DEFAULT); + + tester.invoke(&SpriteThread::unloadSprite); + } + + void stopTest() { + async_->send(); + } + +private: + std::unique_ptr<uv::async> async_; +}; + +TEST_F(SpriteTest, LoadingSuccess) { + SpriteParams params = { + "test/fixtures/resources/sprite", + 1.0, + }; + + auto callback = [this, ¶ms](SpriteStore* spriteStore, std::exception_ptr error) { + ASSERT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + ASSERT_TRUE(error == nullptr); + + ASSERT_TRUE(!spriteStore->getDirty().empty()); + + ASSERT_EQ(spriteStore->pixelRatio, params.pixelRatio); + ASSERT_NE(spriteStore->pixelRatio, 1.5); + ASSERT_NE(spriteStore->pixelRatio, 2.0); + + ASSERT_TRUE(spriteStore->isLoaded()); + + stopTest(); + }; + + MockFileSource fileSource(MockFileSource::Success, ""); + runTest(params, &fileSource, callback); +} + +TEST_F(SpriteTest, LoadingFail) { + SpriteParams params = { + "test/fixtures/resources/sprite", + 1.0, + }; + + auto callback = [this, ¶ms](SpriteStore* spriteStore, std::exception_ptr error) { + ASSERT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + ASSERT_TRUE(error != nullptr); + + ASSERT_EQ(spriteStore->pixelRatio, params.pixelRatio); + ASSERT_NE(spriteStore->pixelRatio, 1.5); + ASSERT_NE(spriteStore->pixelRatio, 2.0); + + ASSERT_FALSE(spriteStore->isLoaded()); + + stopTest(); + }; + + MockFileSource fileSourceFailSpriteJSON(MockFileSource::RequestFail, "sprite.json"); + runTest(params, &fileSourceFailSpriteJSON, callback); + + MockFileSource fileSourceFailSpriteImage(MockFileSource::RequestFail, "sprite.png"); + runTest(params, &fileSourceFailSpriteImage, callback); + + MockFileSource fileSourceCorruptedSpriteJSON(MockFileSource::RequestWithCorruptedData, "sprite.json"); + runTest(params, &fileSourceCorruptedSpriteJSON, callback); + + MockFileSource fileSourceCorruptedSpriteImage(MockFileSource::RequestWithCorruptedData, "sprite.png"); + runTest(params, &fileSourceCorruptedSpriteImage, callback); +} + +TEST_F(SpriteTest, LoadingCancel) { + SpriteParams params = { + "test/fixtures/resources/sprite", + 1.0, + }; + + auto callback = [this](SpriteStore*, std::exception_ptr) { + FAIL() << "Should never be called"; + }; + + MockFileSource fileSourceDelaySpriteJSON(MockFileSource::SuccessWithDelay, "sprite.json"); + fileSourceDelaySpriteJSON.setOnRequestDelayedCallback([this]{ + stopTest(); + }); + runTest(params, &fileSourceDelaySpriteJSON, callback); + + MockFileSource fileSourceDelaySpriteImage(MockFileSource::SuccessWithDelay, "sprite.png"); + fileSourceDelaySpriteImage.setOnRequestDelayedCallback([this]{ + stopTest(); + }); + runTest(params, &fileSourceDelaySpriteImage, callback); +} + +TEST_F(SpriteTest, InvalidURL) { + SpriteParams params = { + "foo bar", + 1.0, + }; + + auto callback = [this](SpriteStore* spriteStore, std::exception_ptr error) { + ASSERT_TRUE(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + ASSERT_TRUE(error != nullptr); + + ASSERT_EQ(spriteStore->isLoaded(), false); + + stopTest(); + }; + + MockFileSource fileSource(MockFileSource::Success, ""); + runTest(params, &fileSource, callback); +} diff --git a/test/test.gypi b/test/test.gypi index e9678b0754..0d66b4c37c 100644 --- a/test/test.gypi +++ b/test/test.gypi @@ -86,7 +86,6 @@ 'style/pending_resources.cpp', 'style/resource_loading.cpp', - 'sprite/sprite.cpp', 'sprite/sprite_atlas.cpp', 'sprite/sprite_image.cpp', 'sprite/sprite_parser.cpp', |