diff --git a/Common/UI/IconCache.cpp b/Common/UI/IconCache.cpp index 7a8ac6c98495..ba8b65006075 100644 --- a/Common/UI/IconCache.cpp +++ b/Common/UI/IconCache.cpp @@ -33,12 +33,10 @@ void IconCache::SaveToFile(FILE *file) { DiskCacheHeader header; header.magic = ICON_CACHE_MAGIC; header.version = ICON_CACHE_VERSION; - header.entryCount = 0; // (uint32_t)cache_.size(); + header.entryCount = (uint32_t)cache_.size(); fwrite(&header, 1, sizeof(header), file); - return; - for (auto &iter : cache_) { DiskCacheEntry entryHeader; entryHeader.keyLen = (uint32_t)iter.first.size(); @@ -142,6 +140,23 @@ bool IconCache::Contains(const std::string &key) { return cache_.find(key) != cache_.end(); } +bool IconCache::MarkPending(const std::string &key) { + std::unique_lock lock(lock_); + if (cache_.find(key) != cache_.end()) { + return false; + } + if (pending_.find(key) != pending_.end()) { + return false; + } + pending_.insert(key); + return true; +} + +void IconCache::Cancel(const std::string &key) { + std::unique_lock lock(lock_); + pending_.erase(key); +} + bool IconCache::InsertIcon(const std::string &key, IconFormat format, std::string &&data) { std::unique_lock lock(lock_); @@ -159,6 +174,8 @@ bool IconCache::InsertIcon(const std::string &key, IconFormat format, std::strin return false; } + pending_.erase(key); + double now = time_now_d(); cache_.emplace(key, Entry{ std::move(data), format, nullptr, now, now, false }); return true; @@ -238,5 +255,7 @@ IconCacheStats IconCache::GetStats() { stats.dataSize += iter.second.data.size(); } + stats.pending = pending_.size(); + return stats; } diff --git a/Common/UI/IconCache.h b/Common/UI/IconCache.h index b9791a0bf735..f1dbe397a2fa 100644 --- a/Common/UI/IconCache.h +++ b/Common/UI/IconCache.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -23,6 +24,7 @@ class Texture; struct IconCacheStats { size_t cachedCount; size_t textureCount; // number of cached images that are "live" textures + size_t pending; size_t dataSize; }; @@ -30,7 +32,9 @@ class IconCache { public: Draw::Texture *BindIconTexture(UIContext *context, const std::string &key); - // It's okay to call this from any thread. + // It's okay to call these from any thread. + bool MarkPending(const std::string &key); // returns false if already pending or loaded + void Cancel(const std::string &key); bool InsertIcon(const std::string &key, IconFormat format, std::string &&pngData); bool GetDimensions(const std::string &key, int *width, int *height); bool Contains(const std::string &key); @@ -56,6 +60,7 @@ class IconCache { void Decimate(); std::map cache_; + std::set pending_; std::mutex lock_; }; diff --git a/UI/Store.cpp b/UI/Store.cpp index 2297539369b0..2682b171cb6b 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -56,12 +56,16 @@ class HttpImageFileView : public UI::View { HttpImageFileView(http::Downloader *downloader, const std::string &path, UI::ImageSizeMode sizeMode = UI::IS_DEFAULT, bool useIconCache = true, UI::LayoutParams *layoutParams = nullptr) : UI::View(layoutParams), path_(path), sizeMode_(sizeMode), downloader_(downloader), useIconCache_(useIconCache) { - if (useIconCache && !g_iconCache.Contains(path_)) { + if (useIconCache && g_iconCache.MarkPending(path_)) { const char *acceptMime = "image/png, image/jpeg, image/*; q=0.9, */*; q=0.8"; downloader_->StartDownloadWithCallback(path_, Path(), [&](http::Download &download) { - std::string data; - download.buffer().TakeAll(&data); - g_iconCache.InsertIcon(path_, IconFormat::PNG, std::move(data)); + if (download.ResultCode() == 200) { + std::string data; + download.buffer().TakeAll(&data); + g_iconCache.InsertIcon(path_, IconFormat::PNG, std::move(data)); + } else { + g_iconCache.Cancel(path_); + } }, acceptMime); } }