diff options
Diffstat (limited to 'src/gui/image/qicon.cpp')
-rw-r--r-- | src/gui/image/qicon.cpp | 154 |
1 files changed, 63 insertions, 91 deletions
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 086ac37a07..07e646efa5 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -32,6 +32,33 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +// Convenience class providing a bool read() function. +namespace { +class ImageReader +{ +public: + ImageReader(const QString &fileName) : m_reader(fileName), m_atEnd(false) { } + + QByteArray format() const { return m_reader.format(); } + + bool read(QImage *image) + { + if (m_atEnd) + return false; + *image = m_reader.read(); + if (!image->size().isValid()) { + m_atEnd = true; + return false; + } + m_atEnd = !m_reader.jumpToNextImage(); + return true; + } + +private: + QImageReader m_reader; + bool m_atEnd; +}; +} // namespace /*! \enum QIcon::Mode @@ -150,7 +177,7 @@ void QPixmapIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode painter->drawPixmap(rect, px); } -static inline int area(const QSize &s) { return s.width() * s.height(); } +static inline qint64 area(const QSize &s) { return qint64(s.width()) * s.height(); } // Returns the smallest of the two that is still larger than or equal to size. // Pixmaps at the correct scale are preferred, pixmaps at lower scale are @@ -160,15 +187,16 @@ static inline int area(const QSize &s) { return s.width() * s.height(); } // the 2x pixmaps then.) static QPixmapIconEngineEntry *bestSizeScaleMatch(const QSize &size, qreal scale, QPixmapIconEngineEntry *pa, QPixmapIconEngineEntry *pb) { - + const auto scaleA = pa->pixmap.devicePixelRatio(); + const auto scaleB = pb->pixmap.devicePixelRatio(); // scale: we can only differentiate on scale if the scale differs - if (pa->scale != pb->scale) { + if (scaleA != scaleB) { // Score the pixmaps: 0 is an exact scale match, positive // scores have more detail than requested, negative scores // have less detail than requested. - qreal ascore = pa->scale - scale; - qreal bscore = pb->scale - scale; + qreal ascore = scaleA - scale; + qreal bscore = scaleB - scale; // always prefer positive scores to prevent upscaling if ((ascore < 0) != (bscore < 0)) @@ -177,18 +205,18 @@ static QPixmapIconEngineEntry *bestSizeScaleMatch(const QSize &size, qreal scale return (qAbs(ascore) < qAbs(bscore)) ? pa : pb; } - int s = area(size); + qint64 s = area(size); if (pa->size == QSize() && pa->pixmap.isNull()) { pa->pixmap = QPixmap(pa->fileName); pa->size = pa->pixmap.size(); } - int a = area(pa->size); + qint64 a = area(pa->size); if (pb->size == QSize() && pb->pixmap.isNull()) { pb->pixmap = QPixmap(pb->fileName); pb->size = pb->pixmap.size(); } - int b = area(pb->size); - int res = a; + qint64 b = area(pb->size); + qint64 res = a; if (qMin(a,b) >= s) res = qMin(a,b); else @@ -201,13 +229,14 @@ static QPixmapIconEngineEntry *bestSizeScaleMatch(const QSize &size, qreal scale QPixmapIconEngineEntry *QPixmapIconEngine::tryMatch(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state) { QPixmapIconEngineEntry *pe = nullptr; - for (int i = 0; i < pixmaps.size(); ++i) - if (pixmaps.at(i).mode == mode && pixmaps.at(i).state == state) { + for (auto &entry : pixmaps) { + if (entry.mode == mode && entry.state == state) { if (pe) - pe = bestSizeScaleMatch(size, scale, &pixmaps[i], pe); + pe = bestSizeScaleMatch(size, scale, &entry, pe); else - pe = &pixmaps[i]; + pe = &entry; } + } return pe; } @@ -271,41 +300,32 @@ QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::St QPixmap QPixmapIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) { - QPixmap pm; QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state, false); if (pe) pm = pe->pixmap; + else + return pm; if (pm.isNull()) { - int idx = pixmaps.size(); - while (--idx >= 0) { - if (pe == &pixmaps.at(idx)) { - pixmaps.remove(idx); - break; - } - } + removePixmapEntry(pe); if (pixmaps.isEmpty()) return pm; - else - return pixmap(size, mode, state); + return scaledPixmap(size, mode, state, scale); } - QSize actualSize = pm.size(); - if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height())) - actualSize.scale(size, Qt::KeepAspectRatio); - + const auto actualSize = adjustSize(size, pm.size()); QString key = "qt_"_L1 % HexString<quint64>(pm.cacheKey()) - % HexString<uint>(pe ? pe->mode : QIcon::Normal) + % HexString<quint8>(pe->mode) % HexString<quint64>(QGuiApplication::palette().cacheKey()) % HexString<uint>(actualSize.width()) % HexString<uint>(actualSize.height()); if (mode == QIcon::Active) { - if (QPixmapCache::find(key % HexString<uint>(mode), &pm)) + if (QPixmapCache::find(key % HexString<quint8>(mode), &pm)) return pm; // horray - if (QPixmapCache::find(key % HexString<uint>(QIcon::Normal), &pm)) { + if (QPixmapCache::find(key % HexString<quint8>(QIcon::Normal), &pm)) { QPixmap active = pm; if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp)) active = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(guiApp))->applyQIconStyleHelper(QIcon::Active, pm); @@ -314,7 +334,7 @@ QPixmap QPixmapIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIc } } - if (!QPixmapCache::find(key % HexString<uint>(mode), &pm)) { + if (!QPixmapCache::find(key % HexString<quint8>(mode), &pm)) { if (pm.size() != actualSize) pm = pm.scaled(actualSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); if (pe->mode != mode && mode != QIcon::Normal) { @@ -324,7 +344,7 @@ QPixmap QPixmapIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIc if (!generated.isNull()) pm = generated; } - QPixmapCache::insert(key % HexString<uint>(mode), pm); + QPixmapCache::insert(key % HexString<quint8>(mode), pm); } return pm; } @@ -341,12 +361,7 @@ QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon:: if (QPixmapIconEngineEntry *pe = bestMatch(size, scale, mode, state, true)) actualSize = pe->size; - if (actualSize.isNull()) - return actualSize; - - if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height())) - actualSize.scale(size, Qt::KeepAspectRatio); - return actualSize; + return adjustSize(size, actualSize); } QList<QSize> QPixmapIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state) @@ -369,7 +384,7 @@ void QPixmapIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon { if (!pixmap.isNull()) { QPixmapIconEngineEntry *pe = tryMatch(pixmap.size(), pixmap.devicePixelRatio(), mode, state); - if (pe && pe->size == pixmap.size() && pe->scale == pixmap.devicePixelRatio()) { + if (pe && pe->size == pixmap.size() && pe->pixmap.devicePixelRatio() == pixmap.devicePixelRatio()) { pe->pixmap = pixmap; pe->fileName.clear(); } else { @@ -387,41 +402,13 @@ static inline int origIcoDepth(const QImage &image) static inline int findBySize(const QList<QImage> &images, const QSize &size) { - for (int i = 0; i < images.size(); ++i) { + for (qsizetype i = 0; i < images.size(); ++i) { if (images.at(i).size() == size) return i; } return -1; } -// Convenience class providing a bool read() function. -namespace { -class ImageReader -{ -public: - ImageReader(const QString &fileName) : m_reader(fileName), m_atEnd(false) {} - - QByteArray format() const { return m_reader.format(); } - - bool read(QImage *image) - { - if (m_atEnd) - return false; - *image = m_reader.read(); - if (!image->size().isValid()) { - m_atEnd = true; - return false; - } - m_atEnd = !m_reader.jumpToNextImage(); - return true; - } - -private: - QImageReader m_reader; - bool m_atEnd; -}; -} // namespace - void QPixmapIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) { if (fileName.isEmpty()) @@ -787,7 +774,6 @@ QIcon &QIcon::operator=(const QIcon &other) /*! \fn void QIcon::swap(QIcon &other) - \since 4.8 Swaps icon \a other with this icon. This operation is very fast and never fails. @@ -805,7 +791,6 @@ QIcon::operator QVariant() const Returns a number that identifies the contents of this QIcon object. Distinct QIcon objects can have the same key if they refer to the same contents. - \since 4.3 The cacheKey() will change when the icon is altered via addPixmap() or addFile(). @@ -862,7 +847,9 @@ QPixmap QIcon::pixmap(const QSize &size, Mode mode, State state) const \since 6.0 Returns a pixmap with the requested \a size, \a devicePixelRatio, \a mode, and \a - state, generating one if necessary. + state, generating one with the given \a mode and \a state if necessary. The pixmap + might be smaller than requested, but never larger, unless the device-pixel ratio + of the returned pixmap is larger than 1. \sa actualSize(), paint() */ @@ -1113,6 +1100,7 @@ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State if (fileName.isEmpty()) return; detach(); + bool alreadyAdded = false; if (!d) { QFileInfo info(fileName); @@ -1122,10 +1110,12 @@ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State suffix = QMimeDatabase().mimeTypeForFile(info).preferredSuffix(); // determination from contents #endif // mimetype QIconEngine *engine = iconEngineFromSuffix(fileName, suffix); + if (engine) + alreadyAdded = !engine->isNull(); d = new QIconPrivate(engine ? engine : new QPixmapIconEngine); } - - d->engine->addFile(fileName, size, mode, state); + if (!alreadyAdded) + d->engine->addFile(fileName, size, mode, state); // Check if a "@Nx" file exists and add it. QString atNxFileName = qt_findAtNxFile(fileName, qApp->devicePixelRatio()); @@ -1134,8 +1124,6 @@ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State } /*! - \since 4.5 - Returns a list of available icon sizes for the specified \a mode and \a state. */ @@ -1147,8 +1135,6 @@ QList<QSize> QIcon::availableSizes(Mode mode, State state) const } /*! - \since 4.7 - Returns the name used to create the icon, if available. Depending on the way the icon was created, it may have an associated @@ -1164,8 +1150,6 @@ QString QIcon::name() const } /*! - \since 4.6 - Sets the search paths for icon themes to \a paths. The content of \a paths should follow the theme format @@ -1179,8 +1163,6 @@ void QIcon::setThemeSearchPaths(const QStringList &paths) } /*! - \since 4.6 - Returns the search paths for icon themes. The default search paths will be defined by the platform. @@ -1235,8 +1217,6 @@ void QIcon::setFallbackSearchPaths(const QStringList &paths) } /*! - \since 4.6 - Sets the current icon theme to \a name. The theme will be will be looked up in themeSearchPaths(). @@ -1255,8 +1235,6 @@ void QIcon::setThemeName(const QString &name) } /*! - \since 4.6 - Returns the name of the current icon theme. If not set, the current icon theme will be defined by the @@ -1317,8 +1295,6 @@ void QIcon::setFallbackThemeName(const QString &name) } /*! - \since 4.6 - Returns the QIcon corresponding to \a name in the \l{themeName()}{current icon theme}. @@ -1388,8 +1364,6 @@ QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback) } /*! - \since 4.6 - Returns \c true if there is an icon available for \a name in the current icon theme or any of the fallbacks, as described by fromTheme(), otherwise returns \c false. @@ -1836,7 +1810,6 @@ bool QIcon::isMask() const /*! \fn QDataStream &operator<<(QDataStream &stream, const QIcon &icon) \relates QIcon - \since 4.2 Writes the given \a icon to the given \a stream as a PNG image. If the icon contains more than one image, all images will @@ -1877,7 +1850,6 @@ QDataStream &operator<<(QDataStream &s, const QIcon &icon) /*! \fn QDataStream &operator>>(QDataStream &stream, QIcon &icon) \relates QIcon - \since 4.2 Reads an image, or a set of images, from the given \a stream into the given \a icon. |