diff options
author | Mitch Curtis <mitch.curtis@qt.io> | 2017-01-04 16:27:52 +0100 |
---|---|---|
committer | Mitch Curtis <mitch.curtis@qt.io> | 2017-02-01 13:58:01 +0000 |
commit | f299b565b5904e39a47b6133643448e46810f0ed (patch) | |
tree | 0620b697a19d6771539d7b36602b28980d5da62c /src/gui/image/qiconloader.cpp | |
parent | f6c17c37ba4e588a8c9a579cfbfb40709fe7cf0e (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.cpp | 48 |
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); } |