#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { static SpriteLoaderObserver nullObserver; struct SpriteLoader::Data { std::shared_ptr image; std::shared_ptr json; std::unique_ptr jsonRequest; std::unique_ptr spriteRequest; }; SpriteLoader::SpriteLoader(float pixelRatio_) : pixelRatio(pixelRatio_), observer(&nullObserver), threadPool(Scheduler::GetBackground()) {} SpriteLoader::~SpriteLoader() = default; void SpriteLoader::load(const std::string& url, FileSource& fileSource) { if (url.empty()) { // Treat a non-existent sprite as a successfully loaded empty sprite. observer->onSpriteLoaded({}); return; } data = std::make_unique(); data->jsonRequest = fileSource.request(Resource::spriteJSON(url, pixelRatio), [this](Response res) { if (res.error) { observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message))); } else if (res.notModified) { return; } else if (res.noContent) { data->json = std::make_shared(); emitSpriteLoadedIfComplete(); } else { // Only trigger a sprite loaded event we got new data. assert(data->json != res.data); data->json = std::move(res.data); emitSpriteLoadedIfComplete(); } }); data->spriteRequest = fileSource.request(Resource::spriteImage(url, pixelRatio), [this](Response res) { if (res.error) { observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message))); } else if (res.notModified) { return; } else if (res.noContent) { data->image = std::make_shared(); emitSpriteLoadedIfComplete(); } else { assert(data->image != res.data); data->image = std::move(res.data); emitSpriteLoadedIfComplete(); } }); } void SpriteLoader::emitSpriteLoadedIfComplete() { assert(data); if (!data->image || !data->json) { return; } struct ParseResult { std::vector> images; std::exception_ptr error; }; auto parseClosure = [image = data->image, json = data->json]() -> ParseResult { try { return {parseSprite(*image, *json), nullptr}; } catch (...) { return {{}, std::current_exception()}; } }; auto resultClosure = [this, weak = weakFactory.makeWeakPtr()](ParseResult result) { if (!weak) return; // This instance has been deleted. if (result.error) { observer->onSpriteError(result.error); return; } observer->onSpriteLoaded(std::move(result.images)); }; threadPool->scheduleAndReplyValue(parseClosure, resultClosure); } void SpriteLoader::setObserver(SpriteLoaderObserver* observer_) { observer = observer_; } } // namespace mbgl