Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iconloader scaling enhancemets #275

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions src/xdgiconloader/xdgiconloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -685,45 +686,55 @@ 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)
{
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

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;
}
}
Expand All @@ -739,6 +750,7 @@ QIconLoaderEngineEntry *XdgIconLoaderEngine::entryForSize(const QSize &size, int
closestMatch = entry;
}
}
m_entryForSize.emplace(std::make_pair(std::move(key), closestMatch));
return closestMatch;
}

Expand All @@ -756,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<ScalableEntry *>(entry))
Expand Down Expand Up @@ -961,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);

Expand Down Expand Up @@ -1010,7 +1024,7 @@ void XdgIconLoaderEngine::virtual_hook(int id, void *data)
QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast<QIconEngine::ScaledPixmapArgument*>(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;
Expand Down
1 change: 1 addition & 0 deletions src/xdgiconloader/xdgiconloader_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class XDGICONLOADER_EXPORT XdgIconLoaderEngine : public QIconEngine
QThemeIconInfo m_info;
QString m_iconName;
uint m_key;
std::map<std::tuple<int, int>, QIconLoaderEngineEntry *> m_entryForSize;

friend class XdgIconLoader;
};
Expand Down