summaryrefslogtreecommitdiffstats
path: root/src/gui/image/qiconloader.cpp
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2017-01-04 16:27:52 +0100
committerMitch Curtis <mitch.curtis@qt.io>2017-02-01 13:58:01 +0000
commitf299b565b5904e39a47b6133643448e46810f0ed (patch)
tree0620b697a19d6771539d7b36602b28980d5da62c /src/gui/image/qiconloader.cpp
parentf6c17c37ba4e588a8c9a579cfbfb40709fe7cf0e (diff)
Implement support for Scale directory key according to Icon Theme spec
Qt already supports high DPI icons using the “@nx” approach, where the device pixel ratio that the image was designed for is in the file name. However, our implementation of the freedekstop.org Icon Theme specification did not support the Scale directory key: https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#directory_layout This meant that users creating icons via QIcon::fromTheme() did not get high DPI support. This patch fixes that. [ChangeLog][QtGui][QIcon] Implemented support for Scale directory key according to Icon Theme Spec. Icons created via QIcon::fromTheme() now have high DPI support by specifying the Scale in the appropriate entry of the relevant index.theme file. Task-number: QTBUG-49820 Change-Id: If442fbc551034166d88defe607109de1c6ca1d28 Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> Reviewed-by: Topi Reiniö <topi.reinio@qt.io> Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'src/gui/image/qiconloader.cpp')
-rw-r--r--src/gui/image/qiconloader.cpp48
1 files changed, 34 insertions, 14 deletions
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
index 324f13a17b..d72c05a3c5 100644
--- a/src/gui/image/qiconloader.cpp
+++ b/src/gui/image/qiconloader.cpp
@@ -47,6 +47,7 @@
#include <qpa/qplatformtheme.h>
#include <QtGui/QIconEngine>
#include <QtGui/QPalette>
+#include <QtCore/qmath.h>
#include <QtCore/QList>
#include <QtCore/QDir>
#include <QtCore/QSettings>
@@ -347,6 +348,10 @@ QIconTheme::QIconTheme(const QString &themeName)
dirInfo.maxSize = indexReader.value(directoryKey +
QLatin1String("/MaxSize"),
size).toInt();
+
+ dirInfo.scale = indexReader.value(directoryKey +
+ QLatin1String("/Scale"),
+ 1).toInt();
m_keyList.append(dirInfo);
}
}
@@ -553,8 +558,11 @@ void QIconLoaderEngine::paint(QPainter *painter, const QRect &rect,
* This algorithm is defined by the freedesktop spec:
* http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
*/
-static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize)
+static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize, int iconscale)
{
+ if (dir.scale != iconscale)
+ return false;
+
if (dir.type == QIconDirInfo::Fixed) {
return dir.size == iconsize;
@@ -575,24 +583,25 @@ static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize)
* 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)
+static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int iconscale)
{
+ const int scaledIconSize = iconsize * iconscale;
if (dir.type == QIconDirInfo::Fixed) {
- return qAbs(dir.size - iconsize);
+ return qAbs(dir.size * dir.scale - scaledIconSize);
} else if (dir.type == QIconDirInfo::Scalable) {
- if (iconsize < dir.minSize)
- return dir.minSize - iconsize;
- else if (iconsize > dir.maxSize)
- return iconsize - dir.maxSize;
+ if (scaledIconSize < dir.minSize * dir.scale)
+ return dir.minSize * dir.scale - scaledIconSize;
+ else if (scaledIconSize > dir.maxSize * dir.scale)
+ return scaledIconSize - dir.maxSize * dir.scale;
else
return 0;
} else if (dir.type == QIconDirInfo::Threshold) {
- if (iconsize < dir.size - dir.threshold)
- return dir.minSize - iconsize;
- else if (iconsize > dir.size + dir.threshold)
- return iconsize - dir.maxSize;
+ if (scaledIconSize < (dir.size - dir.threshold) * dir.scale)
+ return dir.minSize * dir.scale - scaledIconSize;
+ else if (scaledIconSize > (dir.size + dir.threshold) * dir.scale)
+ return scaledIconSize - dir.maxSize * dir.scale;
else return 0;
}
@@ -600,7 +609,7 @@ static int directorySizeDistance(const QIconDirInfo &dir, int iconsize)
return INT_MAX;
}
-QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
+QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size, int scale)
{
int iconsize = qMin(size.width(), size.height());
@@ -612,7 +621,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
// Search for exact matches first
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_info.entries.at(i);
- if (directoryMatchesSize(entry->dir, iconsize)) {
+ if (directoryMatchesSize(entry->dir, iconsize, scale)) {
return entry;
}
}
@@ -622,7 +631,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
QIconLoaderEngineEntry *closestMatch = 0;
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_info.entries.at(i);
- int distance = directorySizeDistance(entry->dir, iconsize);
+ int distance = directorySizeDistance(entry->dir, iconsize, scale);
if (distance < minimalSize) {
minimalSize = distance;
closestMatch = entry;
@@ -665,6 +674,8 @@ QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State st
basePixmap.load(filename);
QSize actualSize = basePixmap.size();
+ // If the size of the best match we have (basePixmap) is larger than the
+ // requested size, we downscale it to match.
if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
actualSize.scale(size, Qt::KeepAspectRatio);
@@ -748,6 +759,15 @@ void QIconLoaderEngine::virtual_hook(int id, void *data)
*reinterpret_cast<bool*>(data) = m_info.entries.isEmpty();
}
break;
+ case QIconEngine::ScaledPixmapHook:
+ {
+ 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);
+ arg.pixmap = entry ? entry->pixmap(arg.size, arg.mode, arg.state) : QPixmap();
+ }
+ break;
default:
QIconEngine::virtual_hook(id, data);
}