diff --git a/autotests/kiconengine_unittest.cpp b/autotests/kiconengine_unittest.cpp index 60476df..f758ac6 100644 --- a/autotests/kiconengine_unittest.cpp +++ b/autotests/kiconengine_unittest.cpp @@ -1,151 +1,145 @@ /* Copyright (C) 2016 David Rosca This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include extern KICONTHEMES_EXPORT int kiconloader_ms_between_checks; class KIconEngine_UnitTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { QStandardPaths::setTestModeEnabled(true); // Remove icon cache const QString cacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/icon-cache.kcache"; QFile::remove(cacheFile); KConfigGroup cg(KSharedConfig::openConfig(), "Icons"); cg.writeEntry("Theme", "oxygen"); cg.sync(); QDir testDataDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)); testIconsDir = QDir(testDataDir.absoluteFilePath(QStringLiteral("icons"))); // we will be recursively deleting these, so a sanity check is in order QVERIFY(testIconsDir.absolutePath().contains(QStringLiteral("qttest"))); testIconsDir.removeRecursively(); // set up a minimal Oxygen icon theme, in case it is not installed QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/apps"))); QVERIFY(QFile::copy(QStringLiteral(":/oxygen.theme"), testIconsDir.filePath(QStringLiteral("oxygen/index.theme")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/apps/kde.png")))); QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/actions"))); // we need the dir to exist since KIconThemes caches mDirs // Clear SHM cache KIconLoader::global()->reconfigure(QString()); } void testValidIconName() { QIcon icon(new KIconEngine(QStringLiteral("kde"), KIconLoader::global())); QVERIFY(!icon.isNull()); QVERIFY(!icon.name().isEmpty()); } void testInvalidIconName() { QIcon icon(new KIconEngine(QStringLiteral("invalid-icon-name"), KIconLoader::global())); -#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) - QEXPECT_FAIL("", "IsNullHook needs Qt 5.7", Continue); -#endif QVERIFY(icon.isNull()); QVERIFY2(icon.name().isEmpty(), qPrintable(icon.name())); } void testUnknownIconNotCached() // QIcon version of the test in kiconloader_unittest.cpp { -#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) - QSKIP("IsNullHook needs Qt 5.7"); -#endif // This is a test to ensure that "unknown" icons are cached as unknown // for performance reasons, but after a while they'll be looked up again // so that newly installed icons can be used without a reboot. kiconloader_ms_between_checks = 500000; QString actionIconsSubdir = QStringLiteral("oxygen/22x22/actions"); QVERIFY(testIconsDir.mkpath(actionIconsSubdir)); QString actionIconsDir = testIconsDir.filePath(actionIconsSubdir); QString nonExistingIconName = QStringLiteral("asvdfg_fhqwhgds"); QString newIconPath = actionIconsDir + QLatin1String("/") + nonExistingIconName + QLatin1String(".png"); QFile::remove(newIconPath); // Find a non-existent icon QIcon icon(new KIconEngine(nonExistingIconName, KIconLoader::global())); QVERIFY(icon.isNull()); QVERIFY(icon.name().isEmpty()); // Install the existing icon by copying. QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), newIconPath)); // Attempt to find the icon again, the cache will still be used for now. QIcon icon2(new KIconEngine(nonExistingIconName, KIconLoader::global())); QVERIFY(icon2.isNull()); QVERIFY(icon2.name().isEmpty()); // Force a recheck to happen on next lookup kiconloader_ms_between_checks = 0; // Verify the icon can now be found. QIcon nowExistingIcon(new KIconEngine(nonExistingIconName, KIconLoader::global())); QVERIFY(!nowExistingIcon.isNull()); QCOMPARE(nowExistingIcon.name(), nonExistingIconName); // And verify again, this time with the cache kiconloader_ms_between_checks = 50000; QIcon icon3(new KIconEngine(nonExistingIconName, KIconLoader::global())); QVERIFY(!icon3.isNull()); QCOMPARE(icon3.name(), nonExistingIconName); } void testCenterIcon() { QIcon icon(new KIconEngine(QStringLiteral("kde"), KIconLoader::global())); QVERIFY(!icon.isNull()); // "kde" icon is actually "test-22x22.png", so this is original icon image const QImage image = icon.pixmap(22, 22).toImage(); // center vertically QVERIFY(icon.pixmap(22, 26).toImage().copy(0, 2, 22, 22) == image); // center horizontally QVERIFY(icon.pixmap(26, 22).toImage().copy(2, 0, 22, 22) == image); } private: QDir testIconsDir; }; QTEST_MAIN(KIconEngine_UnitTest) #include "kiconengine_unittest.moc" diff --git a/autotests/kiconloader_benchmark.cpp b/autotests/kiconloader_benchmark.cpp index 37e557b..eb0f71b 100644 --- a/autotests/kiconloader_benchmark.cpp +++ b/autotests/kiconloader_benchmark.cpp @@ -1,138 +1,132 @@ /* This file is part of the KDE libraries Copyright 2016 Aleix Pol Gonzalez This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include class KIconLoader_Benchmark : public QObject { Q_OBJECT private Q_SLOTS: void init() { #if 0 // Enable this code to benchmark very first startup. // Starting the application again uses the on-disk cache, so actually benchmarking -with- a cache is more relevant. // Remove icon cache const QString cacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/icon-cache.kcache"; QFile::remove(cacheFile); // Clear SHM cache KIconLoader::global()->reconfigure(QString()); #endif } void benchmarkExistingIcons() { //icon list I get to load kwrite static QStringList icons = { QStringLiteral("accessories-text-editor"), QStringLiteral("bookmarks"), QStringLiteral("dialog-close"), QStringLiteral("edit-cut"), QStringLiteral("edit-paste"), QStringLiteral("edit-copy"), QStringLiteral("document-save"), QStringLiteral("edit-undo"), QStringLiteral("edit-redo"), QStringLiteral("code-context"), QStringLiteral("document-print"), QStringLiteral("document-print-preview"), QStringLiteral("view-refresh"), QStringLiteral("document-save-as"), QStringLiteral("preferences-other"), QStringLiteral("edit-select-all"), QStringLiteral("zoom-in"), QStringLiteral("zoom-out"), QStringLiteral("edit-find"), QStringLiteral("go-down-search"), QStringLiteral("go-up-search"), QStringLiteral("tools-check-spelling"), QStringLiteral("bookmark-new"), QStringLiteral("format-indent-more"), QStringLiteral("format-indent-less"), QStringLiteral("text-plain"), QStringLiteral("go-up"), QStringLiteral("go-down"), QStringLiteral("dialog-ok"), QStringLiteral("dialog-cancel"), QStringLiteral("window-close"), QStringLiteral("document-new"), QStringLiteral("document-open"), QStringLiteral("document-open-recent"), QStringLiteral("window-new"), QStringLiteral("application-exit"), QStringLiteral("show-menu"), QStringLiteral("configure-shortcuts"), QStringLiteral("configure-toolbars"), QStringLiteral("help-contents"), QStringLiteral("help-contextual"), QStringLiteral("tools-report-bug"), QStringLiteral("preferences-desktop-locale"), QStringLiteral("kde") }; QBENCHMARK { foreach (const QString &iconName, icons) { const QIcon icon = QIcon::fromTheme(iconName); if(icon.isNull()) QSKIP("missing icons"); QVERIFY(!icon.pixmap(24, 24).isNull()); //QVERIFY(!icon.pixmap(512, 512).isNull()); } } } void benchmarkNonExistingIcon_notCached() { -#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) - QSKIP("IsNullHook needs Qt 5.7"); -#endif QBENCHMARK { // Remove icon cache const QString cacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/icon-cache.kcache"; QFile::remove(cacheFile); // Clear SHM cache KIconLoader::global()->reconfigure(QString()); QIcon icon(new KIconEngine(QStringLiteral("invalid-icon-name"), KIconLoader::global())); QVERIFY(icon.isNull()); QVERIFY2(icon.name().isEmpty(), qPrintable(icon.name())); QVERIFY(!icon.pixmap(QSize(16, 16), QIcon::Normal).isNull()); } } void benchmarkNonExistingIcon_cached() { -#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) - QSKIP("IsNullHook needs Qt 5.7"); -#endif QBENCHMARK { QIcon icon(new KIconEngine(QStringLiteral("invalid-icon-name"), KIconLoader::global())); QVERIFY(icon.isNull()); QVERIFY2(icon.name().isEmpty(), qPrintable(icon.name())); QVERIFY(!icon.pixmap(QSize(16, 16), QIcon::Normal).isNull()); } } }; QTEST_MAIN(KIconLoader_Benchmark) #include "kiconloader_benchmark.moc" diff --git a/src/kiconengine.cpp b/src/kiconengine.cpp index 23789c2..6a69517 100644 --- a/src/kiconengine.cpp +++ b/src/kiconengine.cpp @@ -1,170 +1,162 @@ /* This file is part of the KDE libraries Copyright (C) 2006 Hamish Rodda This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kiconengine.h" #include #include #include #include KIconEngine::KIconEngine(const QString &iconName, KIconLoader *iconLoader, const QStringList &overlays) : mIconName(iconName), mOverlays(overlays), mIconLoader(iconLoader) { } KIconEngine::KIconEngine(const QString &iconName, KIconLoader *iconLoader) : mIconName(iconName), mIconLoader(iconLoader) { } static inline int qIconModeToKIconState(QIcon::Mode mode) { int kstate; switch (mode) { default: case QIcon::Normal: kstate = KIconLoader::DefaultState; break; case QIcon::Active: kstate = KIconLoader::ActiveState; break; case QIcon::Disabled: kstate = KIconLoader::DisabledState; break; case QIcon::Selected: kstate = KIconLoader::SelectedState; break; } return kstate; } QSize KIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) { Q_UNUSED(state) Q_UNUSED(mode) const int iconSize = qMin(size.width(), size.height()); return QSize(iconSize, iconSize); } void KIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) { if (!mIconLoader) { return; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) const qreal dpr = painter->device()->devicePixelRatioF(); -#else - const qreal dpr = painter->device()->devicePixelRatio(); -#endif painter->drawPixmap(rect, pixmap(rect.size() * dpr, mode, state)); } QPixmap KIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) { Q_UNUSED(state) if (size.isEmpty()) { return QPixmap(); } if (!mIconLoader) { QPixmap pm(size); pm.fill(Qt::transparent); return pm; } const int kstate = qIconModeToKIconState(mode); const int iconSize = qMin(size.width(), size.height()); QPixmap pix = mIconLoader.data()->loadIcon(mIconName, KIconLoader::Desktop, iconSize, kstate, mOverlays); if (pix.size() == size) { return pix; } QPixmap pix2(size); pix2.fill(QColor(0, 0, 0, 0)); QPainter painter(&pix2); painter.drawPixmap(QPoint((pix2.width() - pix.width()) / 2, (pix2.height() - pix.height()) / 2), pix); return pix2; } QString KIconEngine::iconName() const { if (!mIconLoader || !mIconLoader->hasIcon(mIconName)) { return QString(); } return mIconName; } Q_GLOBAL_STATIC_WITH_ARGS(QList, sSizes, (QList() << QSize(16, 16) << QSize(22, 22) << QSize(32, 32) << QSize(48, 48) << QSize(64, 64) << QSize(128, 128) << QSize(256, 256))) QList KIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state) const { Q_UNUSED(mode); Q_UNUSED(state); if (!mIconLoader) { return QList(); } bool found = mIconLoader->hasIcon(iconName()); return found ? *sSizes : QList(); } QString KIconEngine::key() const { return QStringLiteral("KIconEngine"); } QIconEngine *KIconEngine::clone() const { return new KIconEngine(mIconName, mIconLoader.data(), mOverlays); } bool KIconEngine::read(QDataStream &in) { in >> mIconName >> mOverlays; return true; } bool KIconEngine::write(QDataStream &out) const { out << mIconName << mOverlays; return true; } void KIconEngine::virtual_hook(int id, void *data) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) if (id == QIconEngine::IsNullHook) { -#else - if (id == 3) { -#endif *reinterpret_cast(data) = !mIconLoader || !mIconLoader->hasIcon(mIconName); } QIconEngine::virtual_hook(id, data); }