IconCache: Know an icon's size before its texture exists

GetDimensions only answered once a texture had been created, so the first
MeasureNotice for a new icon (and after the texture was released for being
unused) measured without it, and the icon was then drawn over the text.
Read the size from the PNG header when the icon is inserted or loaded.

Also remove a width adjustment in MeasureNotice that was overwritten
before use.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-09-30 11:29:17 -06:00
1 parent afe4025106
commit 8b96d109ff
3 files changed
+25 -8

No files matched your search

+23 -7
View File
@@ -1,4 +1,5 @@
#include <algorithm>
#include <cstring>
#include "Common/UI/IconCache.h"
#include "Common/UI/Context.h"
@@ -38,6 +39,20 @@ struct DiskCacheEntry {
};
static_assert(sizeof(DiskCacheEntry) == 24, "DiskCacheEntry is written to disk as is");
// Reads the size from the header, so layout can use it before there's a texture. 0x0 if unknown.
static void PeekIconSize(const std::string &data, IconFormat format, int *width, int *height) {
*width = 0;
*height = 0;
if (format == IconFormat::PNG && data.size() >= sizeof(PNGHeaderPeek)) {
PNGHeaderPeek peek;
memcpy(&peek, data.data(), sizeof(peek));
if (peek.IsValidPNGHeader()) {
*width = peek.Width();
*height = peek.Height();
}
}
}
void IconCache::SaveToFile(FILE *file) {
std::unique_lock<std::mutex> lock(lock_);
@@ -115,6 +130,7 @@ bool IconCache::LoadFromFile(FILE *file) {
entry.format = entryHeader.format;
entry.insertedTimeStamp = entryHeader.insertedTimestamp;
entry.usedTimeStamp = now;
PeekIconSize(entry.data, entry.format, &entry.width, &entry.height);
cache_.emplace(key, entry);
}
@@ -224,14 +240,12 @@ bool IconCache::GetDimensions(std::string_view key, int *width, int *height) {
}
const auto &entry = iter->second;
if (entry.texture) {
// TODO: Store the width/height in the cache.
*width = entry.texture->Width();
*height = entry.texture->Height();
return true;
} else {
if (entry.width <= 0 || entry.height <= 0) {
return false;
}
*width = entry.width;
*height = entry.height;
return true;
}
bool IconCache::Contains(std::string_view key) {
@@ -305,7 +319,9 @@ bool IconCache::InsertIcon(std::string_view key, IconFormat format, std::string
}
double now = time_now_d();
cache_.emplace(key, Entry{ std::move(data), format, nullptr, now, now });
Entry entry{ std::move(data), format, nullptr, now, now };
PeekIconSize(entry.data, entry.format, &entry.width, &entry.height);
cache_.emplace(key, std::move(entry));
return true;
}
+2
View File
@@ -63,6 +63,8 @@ private:
double insertedTimeStamp;
double usedTimeStamp;
double uploadFailedTime; // When CreateTexture last failed, or 0.
int width; // From the image header, 0 if unknown.
int height;
};
std::map<std::string, Entry, std::less<>> cache_;
-1
View File
@@ -54,7 +54,6 @@ void MeasureNotice(const UIContext &dc, NoticeLevel level, std::string_view text
// Normal entry but with a cached icon.
int iconWidth, iconHeight;
if (g_iconCache.GetDimensions(iconName, &iconWidth, &iconHeight)) {
*width += 5.0f + iconWidth;
iconW = iconWidth;
iconH = iconHeight;
}