From b51193920731919b5491fdf0df701886ccd4f4a0 Mon Sep 17 00:00:00 2001 From: Palo Kisa Date: Thu, 3 Mar 2022 10:41:55 +0100 Subject: [PATCH 1/3] iconloader: Build/use map for finding entries Use map to not traverse and evaluate the existing entries each time when info/icon is needed. --- src/xdgiconloader/xdgiconloader.cpp | 8 ++++++++ src/xdgiconloader/xdgiconloader_p.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/xdgiconloader/xdgiconloader.cpp b/src/xdgiconloader/xdgiconloader.cpp index 91515ca..61fe6bc 100644 --- a/src/xdgiconloader/xdgiconloader.cpp +++ b/src/xdgiconloader/xdgiconloader.cpp @@ -641,6 +641,7 @@ void XdgIconLoaderEngine::ensureLoaded() qDeleteAll(m_info.entries); m_info.entries.clear(); m_info.iconName.clear(); + m_entryForSize.clear(); Q_ASSERT(m_info.entries.empty()); m_info = XdgIconLoader::instance()->loadIcon(m_iconName); @@ -714,6 +715,11 @@ static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int icon QIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size, int scale) { int iconsize = qMin(size.width(), size.height()); + const auto key = std::make_pair(iconsize, scale); + const auto i = m_entryForSize.find(key); + if (i != m_entryForSize.cend()) { + return i->second; + } // Note that m_info.entries are sorted so that png-files // come first @@ -724,6 +730,7 @@ QIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size, int for (int i = 0; i < numEntries; ++i) { QIconLoaderEngineEntry *entry = m_info.entries.at(i); if (directoryMatchesSize(entry->dir, iconsize, scale)) { + m_entryForSize.emplace(std::make_pair(std::move(key), entry)); return entry; } } @@ -739,6 +746,7 @@ QIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size, int closestMatch = entry; } } + m_entryForSize.emplace(std::make_pair(std::move(key), closestMatch)); return closestMatch; } diff --git a/src/xdgiconloader/xdgiconloader_p.h b/src/xdgiconloader/xdgiconloader_p.h index ef59443..dd48f4f 100644 --- a/src/xdgiconloader/xdgiconloader_p.h +++ b/src/xdgiconloader/xdgiconloader_p.h @@ -90,6 +90,7 @@ class XDGICONLOADER_EXPORT XdgIconLoaderEngine : public QIconEngine QThemeIconInfo m_info; QString m_iconName; uint m_key; + std::map, QIconLoaderEngineEntry *> m_entryForSize; friend class XdgIconLoader; }; From 99e3649fe2cfe38972d70d2a2bbc6593a54bf69a Mon Sep 17 00:00:00 2001 From: Palo Kisa Date: Thu, 3 Mar 2022 10:54:30 +0100 Subject: [PATCH 2/3] iconloader: Prefer entry with the same scale ..and avoid unneded size multiplication/division. --- src/xdgiconloader/xdgiconloader.cpp | 30 ++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/xdgiconloader/xdgiconloader.cpp b/src/xdgiconloader/xdgiconloader.cpp index 61fe6bc..eb9e44a 100644 --- a/src/xdgiconloader/xdgiconloader.cpp +++ b/src/xdgiconloader/xdgiconloader.cpp @@ -686,30 +686,33 @@ static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize, int icon * This algorithm is defined by the freedesktop spec: * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html */ -static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int iconscale) +static int directorySizeDistance(const QIconDirInfo &dir, int scaledIconSize, int iconscale) { - const int scaledIconSize = iconsize * iconscale; + int distance = 0xffffff; if (dir.type == QIconDirInfo::Fixed) { - return qAbs(dir.size * dir.scale - scaledIconSize); + distance = qAbs(dir.size * dir.scale - scaledIconSize); } else if (dir.type == QIconDirInfo::Scalable) { if (scaledIconSize < dir.minSize * dir.scale) - return dir.minSize * dir.scale - scaledIconSize; + distance = dir.minSize * dir.scale - scaledIconSize; else if (scaledIconSize > dir.maxSize * dir.scale) - return scaledIconSize - dir.maxSize * dir.scale; + distance = scaledIconSize - dir.maxSize * dir.scale; else - return 0; + distance = 0; } else if (dir.type == QIconDirInfo::Threshold) { if (scaledIconSize < (dir.size - dir.threshold) * dir.scale) - return dir.minSize * dir.scale - scaledIconSize; + distance = dir.minSize * dir.scale - scaledIconSize; else if (scaledIconSize > (dir.size + dir.threshold) * dir.scale) - return scaledIconSize - dir.maxSize * dir.scale; - else return 0; + distance = scaledIconSize - dir.maxSize * dir.scale; + else distance = 0; } - Q_ASSERT(1); // Not a valid value - return INT_MAX; + // prefer requested scale + distance <<= 1; + distance |= dir.scale == iconscale ? 0 : 1; + + return distance; } QIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size, int scale) @@ -727,9 +730,10 @@ QIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size, int const int numEntries = m_info.entries.size(); // Search for exact matches first + const int downscaledSize = iconsize / scale; for (int i = 0; i < numEntries; ++i) { QIconLoaderEngineEntry *entry = m_info.entries.at(i); - if (directoryMatchesSize(entry->dir, iconsize, scale)) { + if (directoryMatchesSize(entry->dir, downscaledSize, scale)) { m_entryForSize.emplace(std::make_pair(std::move(key), entry)); return entry; } @@ -1018,7 +1022,7 @@ void XdgIconLoaderEngine::virtual_hook(int id, void *data) QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast(data); // QIcon::pixmap() multiplies size by the device pixel ratio. const int integerScale = qCeil(arg.scale); - QIconLoaderEngineEntry *entry = entryForSize(arg.size / integerScale, integerScale); + QIconLoaderEngineEntry *entry = entryForSize(arg.size, integerScale); arg.pixmap = entry ? entry->pixmap(arg.size, arg.mode, arg.state) : QPixmap(); } break; From 58216164cdd57cfe0a019efb69e6219cf6091c3a Mon Sep 17 00:00:00 2001 From: Palo Kisa Date: Thu, 3 Mar 2022 10:56:34 +0100 Subject: [PATCH 3/3] iconloader: Consider scale in actualSize() & pixmap() These APIs don't provide the scaling information, we will guess it by using the application's one (QIcon does it similarly in such cases). --- src/xdgiconloader/xdgiconloader.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/xdgiconloader/xdgiconloader.cpp b/src/xdgiconloader/xdgiconloader.cpp index eb9e44a..2701b4e 100644 --- a/src/xdgiconloader/xdgiconloader.cpp +++ b/src/xdgiconloader/xdgiconloader.cpp @@ -768,7 +768,8 @@ QSize XdgIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode, ensureLoaded(); - QIconLoaderEngineEntry *entry = entryForSize(size); + const int scale = qCeil(qApp->devicePixelRatio());// Don't know which window to target + QIconLoaderEngineEntry *entry = entryForSize(size, scale); if (entry) { const QIconDirInfo &dir = entry->dir; if (dir.type == QIconDirInfo::Scalable || dynamic_cast(entry)) @@ -973,7 +974,8 @@ QPixmap XdgIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode, { ensureLoaded(); - QIconLoaderEngineEntry *entry = entryForSize(size); + const int scale = qCeil(qApp->devicePixelRatio());// Don't know which window to target + QIconLoaderEngineEntry *entry = entryForSize(size, scale); if (entry) return entry->pixmap(size, mode, state);