Draft: Replace QString cache IDs with a struct-based version
As it turns out, QString::number() is quite expensive, especially when using it in a code path that is called a lot of times. So instead, use a struct with a custom hash method as cache ID. This is significantly faster since we do not need to do memory allocations or string conversions.
This commit is contained in:
parent
b1b91fb3eb
commit
f09b46bec6
@ -33,6 +33,7 @@ target_link_libraries(corebindingsplugin
|
||||
KF5::Declarative
|
||||
KF5::IconThemes
|
||||
KF5::I18n
|
||||
Qt5::Svg
|
||||
KF5::Service #for kplugininfo.h
|
||||
KF5::WindowSystem
|
||||
KF5::Plasma
|
||||
|
@ -83,7 +83,7 @@ ecm_generate_export_header(KF5Plasma
|
||||
GROUP_BASE_NAME KF
|
||||
VERSION ${KF5_VERSION}
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
DEPRECATION_VERSIONS 5.6 5.19 5.28 5.30 5.36 5.46 5.67 5.77
|
||||
DEPRECATION_VERSIONS 5.6 5.19 5.28 5.30 5.36 5.46 5.67 5.77 5.78
|
||||
)
|
||||
# TODO: add support for EXCLUDE_DEPRECATED_BEFORE_AND_AT to all Plasma libs
|
||||
# needs fixing of undeprecated API being still implemented using own deprecated API
|
||||
|
@ -27,7 +27,7 @@
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
QHash<ThemePrivate *, QHash<QString, QWeakPointer<FrameData>> > FrameSvgPrivate::s_sharedFrames;
|
||||
QHash<ThemePrivate *, QHash<uint, QWeakPointer<FrameData>> > FrameSvgPrivate::s_sharedFrames;
|
||||
|
||||
// Any attempt to generate a frame whose width or height is larger than this
|
||||
// will be rejected
|
||||
@ -332,7 +332,7 @@ QRegion FrameSvg::mask() const
|
||||
return result;
|
||||
}
|
||||
|
||||
QString id = d->cacheId(d->frame.data(), QString());
|
||||
uint id = qHash(d->cacheId(d->frame.data(), QString()), SvgRectsCache::s_seed);
|
||||
|
||||
QRegion* obj = d->frame->cachedMasks.object(id);
|
||||
|
||||
@ -459,7 +459,7 @@ QPixmap FrameSvgPrivate::alphaMask()
|
||||
|
||||
QSharedPointer<FrameData> FrameSvgPrivate::lookupOrCreateMaskFrame(const QSharedPointer<FrameData> &frame, const QString &maskPrefix, const QString &maskRequestedPrefix)
|
||||
{
|
||||
const QString key = cacheId(frame.data(), maskPrefix);
|
||||
const uint key = qHash(cacheId(frame.data(), maskPrefix));
|
||||
QSharedPointer<FrameData> mask = s_sharedFrames[q->theme()->d].value(key);
|
||||
|
||||
// See if we can find a suitable candidate in the shared frames.
|
||||
@ -488,17 +488,19 @@ void FrameSvgPrivate::generateBackground(const QSharedPointer<FrameData> &frame)
|
||||
return;
|
||||
}
|
||||
|
||||
const QString id = cacheId(frame.data(), frame->prefix);
|
||||
const uint id = qHash(cacheId(frame.data(), frame->prefix));
|
||||
|
||||
bool frameCached = !frame->cachedBackground.isNull();
|
||||
bool overlayCached = false;
|
||||
//TODO KF6: Kill Overlays
|
||||
const bool overlayAvailable = !frame->prefix.startsWith(QLatin1String("mask-")) && q->hasElement(frame->prefix % QLatin1String("overlay"));
|
||||
QPixmap overlay;
|
||||
if (q->isUsingRenderingCache()) {
|
||||
frameCached = q->theme()->findInCache(id, frame->cachedBackground, frame->lastModified) && !frame->cachedBackground.isNull();
|
||||
frameCached = q->theme()->findInCache(QString::number(id), frame->cachedBackground, frame->lastModified) && !frame->cachedBackground.isNull();
|
||||
|
||||
if (overlayAvailable) {
|
||||
overlayCached = q->theme()->findInCache(QLatin1String("overlay_") % id, overlay, frame->lastModified) && !overlay.isNull();
|
||||
const uint overlayId = qHash(cacheId(frame.data(), frame->prefix % QLatin1String("overlay")));
|
||||
overlayCached = q->theme()->findInCache(QString::number(overlayId), overlay, frame->lastModified) && !overlay.isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,10 +624,10 @@ QRect FrameSvgPrivate::contentGeometry(const QSharedPointer<FrameData> &frame, c
|
||||
void FrameSvgPrivate::updateFrameData(uint lastModified, UpdateType updateType)
|
||||
{
|
||||
auto fd = frame;
|
||||
QString newKey;
|
||||
uint newKey = 0;
|
||||
|
||||
if (fd) {
|
||||
const QString oldKey = fd->cacheId;
|
||||
const uint oldKey = fd->cacheId;
|
||||
|
||||
const QString oldPath = fd->imagePath;
|
||||
const FrameSvg::EnabledBorders oldBorders = fd->enabledBorders;
|
||||
@ -635,7 +637,7 @@ void FrameSvgPrivate::updateFrameData(uint lastModified, UpdateType updateType)
|
||||
fd->frameSize = pendingFrameSize;
|
||||
fd->imagePath = q->imagePath();
|
||||
|
||||
newKey = cacheId(fd.data(), prefix);
|
||||
newKey = qHash(cacheId(fd.data(), prefix));
|
||||
|
||||
//reset frame to old values
|
||||
fd->enabledBorders = oldBorders;
|
||||
@ -671,8 +673,8 @@ void FrameSvgPrivate::updateFrameData(uint lastModified, UpdateType updateType)
|
||||
fd->imagePath = q->imagePath();
|
||||
fd->lastModified = lastModified;
|
||||
//was fd just created empty now?
|
||||
if (newKey.isEmpty()) {
|
||||
newKey = cacheId(fd.data(), prefix);
|
||||
if (newKey == 0) {
|
||||
newKey = qHash(cacheId(fd.data(), prefix));
|
||||
}
|
||||
|
||||
// we know it isn't in s_sharedFrames due to the check above, so insert it now
|
||||
@ -752,11 +754,10 @@ void FrameSvgPrivate::paintCorner(QPainter& p, const QSharedPointer<FrameData> &
|
||||
}
|
||||
}
|
||||
|
||||
QString FrameSvgPrivate::cacheId(FrameData *frame, const QString &prefixToSave) const
|
||||
SvgPrivate::CacheId FrameSvgPrivate::cacheId(FrameData *frame, const QString &prefixToSave) const
|
||||
{
|
||||
const QSize size = frameSize(frame).toSize();
|
||||
const QLatin1Char s('_');
|
||||
return QString::number(frame->enabledBorders) % s % QString::number(size.width()) % s % QString::number(size.height()) % s % QString::number(q->scaleFactor()) % s % QString::number(q->devicePixelRatio()) % s % prefixToSave % s % frame->imagePath;
|
||||
return SvgPrivate::CacheId{double(size.width()), double(size.height()), frame->imagePath, prefixToSave, q->status(), q->scaleFactor(), q->devicePixelRatio(), q->colorGroup(), frame->enabledBorders, q->Svg::d->lastModified};
|
||||
}
|
||||
|
||||
void FrameSvgPrivate::cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay)
|
||||
@ -770,15 +771,16 @@ void FrameSvgPrivate::cacheFrame(const QString &prefixToSave, const QPixmap &bac
|
||||
return;
|
||||
}
|
||||
|
||||
const QString id = cacheId(frame.data(), prefixToSave);
|
||||
const uint id = qHash(cacheId(frame.data(), prefixToSave));
|
||||
|
||||
//qCDebug(LOG_PLASMA)<<"Saving to cache frame"<<id;
|
||||
|
||||
q->theme()->insertIntoCache(id, background, QString::number((qint64)q, 16) % prefixToSave);
|
||||
q->theme()->insertIntoCache(QString::number(id), background, QString::number((qint64)q, 16) % prefixToSave);
|
||||
|
||||
if (!overlay.isNull()) {
|
||||
//insert overlay
|
||||
q->theme()->insertIntoCache(QLatin1String("overlay_") % id, overlay, QString::number((qint64)q, 16) % prefixToSave % QLatin1String("overlay"));
|
||||
const uint overlayId = qHash(cacheId(frame.data(), frame->prefix % QLatin1String("overlay")));
|
||||
q->theme()->insertIntoCache(QString::number(overlayId), overlay, QString::number((qint64)q, 16) % prefixToSave % QLatin1String("overlay"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include <Plasma/Theme>
|
||||
|
||||
#include "svg_p.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
@ -73,12 +75,12 @@ public:
|
||||
QString requestedPrefix;
|
||||
FrameSvg::EnabledBorders enabledBorders;
|
||||
QPixmap cachedBackground;
|
||||
QCache<QString, QRegion> cachedMasks;
|
||||
QCache<uint, QRegion> cachedMasks;
|
||||
static const int MAX_CACHED_MASKS = 10;
|
||||
uint lastModified = 0;
|
||||
|
||||
QSize frameSize;
|
||||
QString cacheId;
|
||||
uint cacheId;
|
||||
|
||||
//measures
|
||||
int topHeight;
|
||||
@ -145,7 +147,7 @@ public:
|
||||
|
||||
void generateBackground(const QSharedPointer<FrameData> &frame);
|
||||
void generateFrameBackground(const QSharedPointer<FrameData> &);
|
||||
QString cacheId(FrameData *frame, const QString &prefixToUse) const;
|
||||
SvgPrivate::CacheId cacheId(FrameData *frame, const QString &prefixToUse) const;
|
||||
void cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay);
|
||||
void updateSizes(FrameData* frame) const;
|
||||
void updateSizes(const QSharedPointer<FrameData> &frame) const { return updateSizes(frame.data()); }
|
||||
@ -178,7 +180,7 @@ public:
|
||||
//this can differ from frame->frameSize if we are in a transition
|
||||
QSize pendingFrameSize;
|
||||
|
||||
static QHash<ThemePrivate *, QHash<QString, QWeakPointer<FrameData>> > s_sharedFrames;
|
||||
static QHash<ThemePrivate *, QHash<uint, QWeakPointer<FrameData>> > s_sharedFrames;
|
||||
|
||||
bool cacheAll : 1;
|
||||
bool repaintBlocked : 1;
|
||||
|
@ -48,11 +48,24 @@ private:
|
||||
class SvgPrivate
|
||||
{
|
||||
public:
|
||||
struct CacheId {
|
||||
double width;
|
||||
double height;
|
||||
QString filePath;
|
||||
QString elementName;
|
||||
int status;
|
||||
double devicePixelRatio;
|
||||
double scaleFactor;
|
||||
int colorGroup;
|
||||
uint extraFlags; //Not used here, used for enabledborders in FrameSvg
|
||||
uint lastModified;
|
||||
};
|
||||
|
||||
SvgPrivate(Svg *svg);
|
||||
~SvgPrivate();
|
||||
|
||||
//This function is meant for the rects cache
|
||||
QString cacheId(const QString &elementId) const;
|
||||
CacheId cacheId(const QString &elementId) const;
|
||||
|
||||
//This function is meant for the pixmap cache
|
||||
QString cachePath(const QString &path, const QSize &size) const;
|
||||
@ -68,7 +81,7 @@ public:
|
||||
void eraseRenderer();
|
||||
|
||||
QRectF elementRect(const QString &elementId);
|
||||
QRectF findAndCacheElementRect(const QString &elementId, const QString &cacheId);
|
||||
QRectF findAndCacheElementRect(const QString &elementId);
|
||||
|
||||
void checkColorHints();
|
||||
|
||||
@ -88,8 +101,6 @@ public:
|
||||
|
||||
Svg *q;
|
||||
QPointer<Theme> theme;
|
||||
QHash<QString, QRectF> localRectCache;
|
||||
QMultiHash<QString, QSize> elementsWithSizeHints;
|
||||
SharedSvgRenderer::Ptr renderer;
|
||||
QString themePath;
|
||||
QString path;
|
||||
@ -111,7 +122,56 @@ public:
|
||||
bool themeFailed : 1;
|
||||
};
|
||||
|
||||
|
||||
class SvgRectsCache : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SvgRectsCache(QObject *parent = nullptr);
|
||||
|
||||
static SvgRectsCache *instance();
|
||||
|
||||
void insert(SvgPrivate::CacheId cacheId, const QRectF &rect, unsigned int lastModified);
|
||||
void insert(uint id, const QString &filePath, const QRectF &rect, unsigned int lastModified);
|
||||
// Those 2 methods are the same, the second uses the integer id produced by hashed CacheId
|
||||
bool findElementRect(SvgPrivate::CacheId cacheId, QRectF &rect);
|
||||
bool findElementRect(uint id, const QString &filePath, QRectF &rect);
|
||||
|
||||
void loadImageFromCache(const QString &path, uint lastModified);
|
||||
void dropImageFromCache(const QString &path);
|
||||
void expireCache(const QString &path);
|
||||
|
||||
void setNaturalSize(const QString &path, qreal scaleFactor, const QSizeF &size);
|
||||
QSizeF naturalSize(const QString &path, qreal scaleFactor);
|
||||
|
||||
QList<QSize> sizeHintsForId(const QString &path, const QString &id);
|
||||
void insertSizeHintForId(const QString &path, const QString &id, const QSize &size);
|
||||
|
||||
QString iconThemePath();
|
||||
void setIconThemePath(const QString &path);
|
||||
|
||||
QStringList cachedKeysForPath(const QString &path) const;
|
||||
|
||||
void updateLastModified(const QString &filePath, unsigned int lastModified);
|
||||
|
||||
static const uint s_seed;
|
||||
|
||||
private:
|
||||
QTimer *m_configSyncTimer = nullptr;
|
||||
QString m_iconThemePath;
|
||||
KSharedConfigPtr m_svgElementsCache;
|
||||
/*
|
||||
* We are indexing in the hash cache ids by their "digested" uint out of qHash(CacheId)
|
||||
* because we need to serialize it and unserialize it to a config file,
|
||||
* which is more efficient to do that with the uint directly rather than a CacheId struct serialization
|
||||
*/
|
||||
QHash<uint, QRectF> m_localRectCache;
|
||||
QHash<QString, QSet<unsigned int>> m_invalidElements;
|
||||
QHash<QString, QList<QSize>> m_sizeHintsForId;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
uint qHash(const Plasma::SvgPrivate::CacheId &id, uint seed = 0);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "theme_p.h"
|
||||
#include "framesvg.h"
|
||||
#include "framesvg_p.h"
|
||||
#include "svg_p.h"
|
||||
#include "debug_p.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
@ -75,12 +76,6 @@ ThemePrivate::ThemePrivate(QObject *parent)
|
||||
pixmapSaveTimer->setInterval(600);
|
||||
QObject::connect(pixmapSaveTimer, &QTimer::timeout, this, &ThemePrivate::scheduledCacheUpdate);
|
||||
|
||||
rectSaveTimer = new QTimer(this);
|
||||
rectSaveTimer->setSingleShot(true);
|
||||
//2 minutes
|
||||
rectSaveTimer->setInterval(2 * 60 * 1000);
|
||||
QObject::connect(rectSaveTimer, &QTimer::timeout, this, &ThemePrivate::saveSvgElementsCache);
|
||||
|
||||
updateNotificationTimer = new QTimer(this);
|
||||
updateNotificationTimer->setSingleShot(true);
|
||||
updateNotificationTimer->setInterval(100);
|
||||
@ -121,7 +116,6 @@ ThemePrivate::ThemePrivate(QObject *parent)
|
||||
|
||||
ThemePrivate::~ThemePrivate()
|
||||
{
|
||||
saveSvgElementsCache();
|
||||
FrameSvgPrivate::s_sharedFrames.remove(this);
|
||||
delete pixmapCache;
|
||||
}
|
||||
@ -239,43 +233,24 @@ bool ThemePrivate::useCache()
|
||||
|
||||
ThemeConfig config;
|
||||
pixmapCache = new KImageCache(cacheFile, config.themeCacheKb() * 1024);
|
||||
pixmapCache->setEvictionPolicy(KSharedDataCache::EvictLeastRecentlyUsed);
|
||||
|
||||
if (cachesTooOld) {
|
||||
discardCache(PixmapCache | SvgElementsCache);
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheTheme && !svgElementsCache) {
|
||||
const QString svgElementsFileNameBase = QLatin1String("plasma-svgelements-") + themeName;
|
||||
QString svgElementsFileName = svgElementsFileNameBase;
|
||||
if (!themeVersion.isEmpty()) {
|
||||
svgElementsFileName += QLatin1String("_v") + themeVersion;
|
||||
}
|
||||
|
||||
// now we check for (and remove) old caches
|
||||
QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation));
|
||||
cacheDir.setNameFilters(QStringList({svgElementsFileNameBase + QLatin1Char('*')}));
|
||||
|
||||
const auto files = cacheDir.entryInfoList();
|
||||
for (const QFileInfo &file : files) {
|
||||
if (!file.absoluteFilePath().endsWith(svgElementsFileName)) {
|
||||
QFile::remove(file.absoluteFilePath());
|
||||
}
|
||||
}
|
||||
|
||||
const QString svgElementsFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1Char('/') + svgElementsFileName;
|
||||
svgElementsCache = KSharedConfig::openConfig(svgElementsFile, KConfig::SimpleConfig);
|
||||
if (cacheTheme) {
|
||||
QString currentIconThemePath;
|
||||
const auto *iconTheme = KIconLoader::global()->theme();
|
||||
if (iconTheme) {
|
||||
currentIconThemePath = iconTheme->dir();
|
||||
}
|
||||
KConfigGroup globalGroup(svgElementsCache, QLatin1String("Global"));
|
||||
const QString oldIconThemePath = globalGroup.readEntry("currentIconThemePath", QString());
|
||||
|
||||
const QString oldIconThemePath = SvgRectsCache::instance()->iconThemePath();
|
||||
if (oldIconThemePath != currentIconThemePath) {
|
||||
discardCache(PixmapCache | SvgElementsCache);
|
||||
globalGroup.writeEntry("currentIconThemePath", currentIconThemePath);
|
||||
svgElementsCache = KSharedConfig::openConfig(svgElementsFile, KConfig::SimpleConfig);
|
||||
SvgRectsCache::instance()->setIconThemePath(currentIconThemePath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,9 +332,6 @@ void ThemePrivate::discardCache(CacheTypes caches)
|
||||
|
||||
if (caches & SvgElementsCache) {
|
||||
discoveries.clear();
|
||||
invalidElements.clear();
|
||||
|
||||
svgElementsCache = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -657,21 +629,6 @@ void ThemePrivate::settingsChanged(bool emitChanges)
|
||||
setThemeName(cg.readEntry("name", ThemePrivate::defaultTheme), false, emitChanges);
|
||||
}
|
||||
|
||||
void ThemePrivate::saveSvgElementsCache()
|
||||
{
|
||||
if (svgElementsCache) {
|
||||
QHashIterator<QString, QSet<QString> > it(invalidElements);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
KConfigGroup imageGroup(svgElementsCache, it.key());
|
||||
imageGroup.writeEntry("invalidElements", it.value().values()); //FIXME: add QSet support to KConfig
|
||||
}
|
||||
|
||||
//Pretty drastic, but this is executed only very rarely
|
||||
svgElementsCache->sync();
|
||||
}
|
||||
}
|
||||
|
||||
QColor ThemePrivate::color(Theme::ColorRole role, Theme::ColorGroup group) const
|
||||
{
|
||||
const KColorScheme *scheme = nullptr;
|
||||
|
@ -78,7 +78,6 @@ public Q_SLOTS:
|
||||
void onAppExitCleanup();
|
||||
void notifyOfChanged();
|
||||
void settingsChanged(bool emitChanges);
|
||||
void saveSvgElementsCache();
|
||||
|
||||
Q_SIGNALS:
|
||||
void themeChanged();
|
||||
@ -116,9 +115,7 @@ public:
|
||||
int defaultWallpaperWidth;
|
||||
int defaultWallpaperHeight;
|
||||
KImageCache *pixmapCache;
|
||||
KSharedConfigPtr svgElementsCache;
|
||||
QString cachedDefaultStyleSheet;
|
||||
QHash<QString, QSet<QString> > invalidElements;
|
||||
QHash<QString, QPixmap> pixmapsToCache;
|
||||
QHash<QString, QString> keysToCache;
|
||||
QHash<QString, QString> idsToCache;
|
||||
@ -126,7 +123,6 @@ public:
|
||||
QHash<Theme::ColorGroup, QString> cachedSelectedSvgStyleSheets;
|
||||
QHash<QString, QString> discoveries;
|
||||
QTimer *pixmapSaveTimer;
|
||||
QTimer *rectSaveTimer;
|
||||
QTimer *updateNotificationTimer;
|
||||
unsigned cacheSize;
|
||||
CacheTypes cachesToDiscard;
|
||||
|
@ -34,9 +34,36 @@
|
||||
#include "theme.h"
|
||||
#include "debug_p.h"
|
||||
|
||||
uint qHash(const Plasma::SvgPrivate::CacheId &id, uint seed)
|
||||
{
|
||||
std::array<uint, 10> parts = {
|
||||
::qHash(id.width),
|
||||
::qHash(id.height),
|
||||
::qHash(id.elementName),
|
||||
::qHash(id.filePath),
|
||||
::qHash(id.status),
|
||||
::qHash(id.devicePixelRatio),
|
||||
::qHash(id.scaleFactor),
|
||||
::qHash(id.colorGroup),
|
||||
::qHash(id.extraFlags),
|
||||
::qHash(id.lastModified)
|
||||
};
|
||||
return qHashRange(parts.begin(), parts.end(), seed);
|
||||
}
|
||||
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class SvgRectsCacheSingleton
|
||||
{
|
||||
public:
|
||||
SvgRectsCache self;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(SvgRectsCacheSingleton, privateSvgRectsCacheSelf)
|
||||
|
||||
const uint SvgRectsCache::s_seed = 0x9e3779b9;
|
||||
|
||||
SharedSvgRenderer::SharedSvgRenderer(QObject *parent)
|
||||
: QSvgRenderer(parent)
|
||||
@ -123,9 +150,217 @@ bool SharedSvgRenderer::load(
|
||||
return true;
|
||||
}
|
||||
|
||||
#define QLSEP QLatin1Char('_')
|
||||
#define CACHE_ID_WITH_SIZE(size, id, status, devicePixelRatio) QString::number(int(size.width())) % QLSEP % QString::number(int(size.height())) % QLSEP % id % QLSEP % QString::number(status) % QLSEP % QString::number(devicePixelRatio)
|
||||
#define CACHE_ID_NATURAL_SIZE(id, status, devicePixelRatio) QLatin1String("Natural") % QLSEP % id % QLSEP % QString::number(status) % QLSEP % QString::number(devicePixelRatio)
|
||||
SvgRectsCache::SvgRectsCache(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
const QString svgElementsFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1Char('/') + QStringLiteral("plasma-svgelements");
|
||||
m_svgElementsCache = KSharedConfig::openConfig(svgElementsFile, KConfig::SimpleConfig);
|
||||
|
||||
m_configSyncTimer = new QTimer(this);
|
||||
m_configSyncTimer->setSingleShot(true);
|
||||
m_configSyncTimer->setInterval(5000);
|
||||
connect(m_configSyncTimer, &QTimer::timeout,
|
||||
this, [this]() {
|
||||
m_svgElementsCache->sync();
|
||||
});
|
||||
}
|
||||
|
||||
SvgRectsCache *SvgRectsCache::instance()
|
||||
{
|
||||
return &privateSvgRectsCacheSelf()->self;
|
||||
}
|
||||
|
||||
void SvgRectsCache::insert(Plasma::SvgPrivate::CacheId cacheId, const QRectF &rect, unsigned int lastModified)
|
||||
{
|
||||
insert(qHash(cacheId, SvgRectsCache::s_seed), cacheId.filePath, rect, lastModified);
|
||||
}
|
||||
|
||||
void SvgRectsCache::insert(uint id, const QString &filePath, const QRectF &rect, unsigned int lastModified)
|
||||
{
|
||||
if (m_localRectCache.contains(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_localRectCache.insert(id, rect);
|
||||
|
||||
KConfigGroup imageGroup(m_svgElementsCache, filePath);
|
||||
imageGroup.writeEntry("LastModified", lastModified);
|
||||
if (rect.isValid()) {
|
||||
imageGroup.writeEntry(QString::number(id), rect);
|
||||
} else {
|
||||
m_invalidElements[filePath] << id;
|
||||
imageGroup.writeEntry("Invalidelements", m_invalidElements[filePath].values());
|
||||
}
|
||||
m_configSyncTimer->start();
|
||||
}
|
||||
|
||||
bool SvgRectsCache::findElementRect(Plasma::SvgPrivate::CacheId cacheId, QRectF &rect)
|
||||
{
|
||||
return findElementRect(qHash(cacheId, SvgRectsCache::s_seed), cacheId.filePath, rect);
|
||||
}
|
||||
|
||||
bool SvgRectsCache::findElementRect(uint id, const QString &filePath, QRectF &rect)
|
||||
{
|
||||
auto it = m_localRectCache.find(id);
|
||||
|
||||
if (it == m_localRectCache.end()) {
|
||||
if (m_invalidElements.contains(filePath) && m_invalidElements[filePath].contains(id)) {
|
||||
rect = QRectF();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
rect = *it;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SvgRectsCache::loadImageFromCache(const QString &path, uint lastModified)
|
||||
{
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
KConfigGroup imageGroup(m_svgElementsCache, path);
|
||||
|
||||
unsigned int savedTime = imageGroup.readEntry("LastModified", 0);
|
||||
|
||||
if (lastModified > savedTime) {
|
||||
imageGroup.deleteGroup();
|
||||
m_configSyncTimer->start();
|
||||
return;
|
||||
}
|
||||
|
||||
auto list = imageGroup.readEntry("Invalidelements", QList<unsigned int>());
|
||||
m_invalidElements[path] = QSet<unsigned int>(list.begin(), list.end());
|
||||
|
||||
for (const auto &key : imageGroup.keyList()) {
|
||||
bool ok = false;
|
||||
if (ok) {
|
||||
const QRectF rect = imageGroup.readEntry(key, QRectF());
|
||||
m_localRectCache.insert(key.toUInt(), rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SvgRectsCache::dropImageFromCache(const QString &path)
|
||||
{
|
||||
KConfigGroup imageGroup(m_svgElementsCache, path);
|
||||
imageGroup.deleteGroup();
|
||||
m_configSyncTimer->start();
|
||||
}
|
||||
|
||||
QList<QSize> SvgRectsCache::sizeHintsForId(const QString &path, const QString &id)
|
||||
{
|
||||
const QString pathId = path % id;
|
||||
|
||||
if (!m_sizeHintsForId.contains(pathId)) {
|
||||
KConfigGroup imageGroup(m_svgElementsCache, path);
|
||||
const QStringList &encoded = imageGroup.readEntry(id, QStringList());
|
||||
QList<QSize> sizes;
|
||||
for (const auto &token : encoded) {
|
||||
const auto &parts = token.split(QLatin1Char('x'));
|
||||
if (parts.size() != 2) {
|
||||
continue;
|
||||
}
|
||||
QSize size = QSize(parts[0].toDouble(), parts[1].toDouble());
|
||||
if (!size.isEmpty()) {
|
||||
sizes << size;
|
||||
}
|
||||
}
|
||||
m_sizeHintsForId[pathId] = sizes;
|
||||
return sizes;
|
||||
}
|
||||
|
||||
return m_sizeHintsForId.value(pathId);
|
||||
}
|
||||
|
||||
void SvgRectsCache::insertSizeHintForId(const QString &path, const QString &id, const QSize &size)
|
||||
{
|
||||
//TODO: need to make this more efficient
|
||||
auto sizeListToString = [] (const QList<QSize> &list) {
|
||||
QString ret;
|
||||
for (const auto &s : list) {
|
||||
ret += QString::number(s.width()) % QLatin1Char('x') % QString::number(s.height()) % QLatin1Char(',');
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
m_sizeHintsForId[path % id].append(size);
|
||||
KConfigGroup imageGroup(m_svgElementsCache, path);
|
||||
imageGroup.writeEntry(id, sizeListToString(m_sizeHintsForId[path % id]));
|
||||
m_configSyncTimer->start();
|
||||
}
|
||||
|
||||
QString SvgRectsCache::iconThemePath()
|
||||
{
|
||||
if (!m_iconThemePath.isEmpty()) {
|
||||
return m_iconThemePath;
|
||||
}
|
||||
|
||||
KConfigGroup imageGroup(m_svgElementsCache, QStringLiteral("General"));
|
||||
m_iconThemePath = imageGroup.readEntry(QStringLiteral("IconThemePath"), QString());
|
||||
|
||||
return m_iconThemePath;
|
||||
}
|
||||
|
||||
void SvgRectsCache::setIconThemePath(const QString &path)
|
||||
{
|
||||
m_iconThemePath = path;
|
||||
KConfigGroup imageGroup(m_svgElementsCache, QStringLiteral("General"));
|
||||
imageGroup.writeEntry(QStringLiteral("IconThemePath"), path);
|
||||
m_configSyncTimer->start();
|
||||
}
|
||||
|
||||
void SvgRectsCache::expireCache(const QString &path)
|
||||
{
|
||||
KConfigGroup imageGroup(m_svgElementsCache, path);
|
||||
|
||||
unsigned int savedTime = imageGroup.readEntry("LastModified", QDateTime().toSecsSinceEpoch());
|
||||
QFileInfo info(path);
|
||||
if (info.exists()) {
|
||||
unsigned int lastModified = info.lastModified().toSecsSinceEpoch();
|
||||
if (lastModified <= savedTime) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
imageGroup.deleteGroup();
|
||||
}
|
||||
|
||||
void SvgRectsCache::setNaturalSize(const QString &path, qreal scaleFactor, const QSizeF &size)
|
||||
{
|
||||
KConfigGroup imageGroup(m_svgElementsCache, path);
|
||||
|
||||
// FIXME: needs something faster, perhaps even sprintf
|
||||
imageGroup.writeEntry(QStringLiteral("NaturalSize_") % QString::number(scaleFactor), size);
|
||||
m_configSyncTimer->start();
|
||||
}
|
||||
|
||||
QSizeF SvgRectsCache::naturalSize(const QString &path, qreal scaleFactor)
|
||||
{
|
||||
KConfigGroup imageGroup(m_svgElementsCache, path);
|
||||
|
||||
// FIXME: needs something faster, perhaps even sprintf
|
||||
return imageGroup.readEntry(QStringLiteral("NaturalSize_") % QString::number(scaleFactor), QSizeF());
|
||||
}
|
||||
|
||||
QStringList SvgRectsCache::cachedKeysForPath(const QString &path) const
|
||||
{
|
||||
KConfigGroup imageGroup(m_svgElementsCache, path);
|
||||
QStringList list = imageGroup.keyList();
|
||||
QStringList filtered;
|
||||
|
||||
std::copy_if (list.begin(), list.end(), std::back_inserter(filtered), [](const QString element){bool ok; element.toLong(&ok); return ok;} );
|
||||
return filtered;
|
||||
}
|
||||
|
||||
void SvgRectsCache::updateLastModified(const QString &filePath, unsigned int lastModified)
|
||||
{
|
||||
KConfigGroup imageGroup(m_svgElementsCache, filePath);
|
||||
imageGroup.writeEntry("LastModified", lastModified);
|
||||
m_configSyncTimer->start();
|
||||
}
|
||||
|
||||
SvgPrivate::SvgPrivate(Svg *svg)
|
||||
: q(svg),
|
||||
@ -153,19 +388,17 @@ SvgPrivate::~SvgPrivate()
|
||||
}
|
||||
|
||||
//This function is meant for the rects cache
|
||||
QString SvgPrivate::cacheId(const QString &elementId) const
|
||||
SvgPrivate::CacheId SvgPrivate::cacheId(const QString &elementId) const
|
||||
{
|
||||
if (size.isValid() && size != naturalSize) {
|
||||
return CACHE_ID_WITH_SIZE(size, elementId, status, devicePixelRatio);
|
||||
} else {
|
||||
return CACHE_ID_NATURAL_SIZE(elementId, status, devicePixelRatio);
|
||||
}
|
||||
auto idSize = size.isValid() && size != naturalSize ? size : QSizeF{-1.0, -1.0};
|
||||
return CacheId{idSize.width(), idSize.height(), path, elementId, status, devicePixelRatio, scaleFactor, -1, 0, lastModified};
|
||||
}
|
||||
|
||||
//This function is meant for the pixmap cache
|
||||
QString SvgPrivate::cachePath(const QString &path, const QSize &size) const
|
||||
QString SvgPrivate::cachePath(const QString &id, const QSize &size) const
|
||||
{
|
||||
return CACHE_ID_WITH_SIZE(size, path, status, devicePixelRatio) % QLSEP % QString::number(colorGroup);
|
||||
auto cacheId = CacheId{double(size.width()), double(size.height()), path, id, status, devicePixelRatio, scaleFactor, colorGroup, 0, lastModified};
|
||||
return QString::number(qHash(cacheId, SvgRectsCache::s_seed));
|
||||
}
|
||||
|
||||
bool SvgPrivate::setImagePath(const QString &imagePath)
|
||||
@ -207,8 +440,7 @@ bool SvgPrivate::setImagePath(const QString &imagePath)
|
||||
themed = isThemed;
|
||||
path.clear();
|
||||
themePath.clear();
|
||||
localRectCache.clear();
|
||||
elementsWithSizeHints.clear();
|
||||
|
||||
bool oldFromCurrentTheme = fromCurrentTheme;
|
||||
fromCurrentTheme = !inIconTheme && isThemed && actualTheme()->currentThemeHasImage(imagePath);
|
||||
|
||||
@ -234,6 +466,12 @@ bool SvgPrivate::setImagePath(const QString &imagePath)
|
||||
#endif
|
||||
}
|
||||
|
||||
QFileInfo info(path);
|
||||
|
||||
lastModified = info.lastModified().toSecsSinceEpoch();
|
||||
|
||||
SvgRectsCache::instance()->loadImageFromCache(path, lastModified);
|
||||
|
||||
// check if svg wants colorscheme applied
|
||||
checkColorHints();
|
||||
|
||||
@ -242,20 +480,14 @@ bool SvgPrivate::setImagePath(const QString &imagePath)
|
||||
if ((themed && !path.isEmpty() && QFileInfo::exists(path)) || QFileInfo::exists(actualPath)) {
|
||||
QRectF rect;
|
||||
|
||||
if (cacheAndColorsTheme()->findInRectsCache(path, QStringLiteral("_Natural_%1").arg(scaleFactor), rect)) {
|
||||
naturalSize = rect.size();
|
||||
} else {
|
||||
naturalSize = SvgRectsCache::instance()->naturalSize(path, scaleFactor);
|
||||
if (naturalSize.isEmpty()) {
|
||||
createRenderer();
|
||||
naturalSize = renderer->defaultSize() * scaleFactor;
|
||||
//qCDebug(LOG_PLASMA) << "natural size for" << path << "from renderer is" << naturalSize;
|
||||
cacheAndColorsTheme()->insertIntoRectsCache(path, QStringLiteral("_Natural_%1").arg(scaleFactor), QRectF(QPointF(0, 0), naturalSize));
|
||||
//qCDebug(LOG_PLASMA) << "natural size for" << path << "from cache is" << naturalSize;
|
||||
SvgRectsCache::instance()->setNaturalSize(path, scaleFactor, naturalSize);
|
||||
}
|
||||
}
|
||||
|
||||
QFileInfo info(path);
|
||||
lastModified = info.lastModified().toSecsSinceEpoch();
|
||||
|
||||
q->resize();
|
||||
emit q->imagePathChanged();
|
||||
|
||||
@ -291,39 +523,15 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, qreal ratio, const QSi
|
||||
QSize size;
|
||||
QString actualElementId;
|
||||
|
||||
if (elementsWithSizeHints.isEmpty()) {
|
||||
// Fetch all size hinted element ids from the theme's rect cache
|
||||
// and store them locally.
|
||||
const QRegularExpression sizeHintedKeyExpr(QLatin1String("^") + CACHE_ID_NATURAL_SIZE(QStringLiteral("(\\d+)-(\\d+)-(.+)"), status, ratio) + QLatin1String("$"));
|
||||
|
||||
const auto lst = cacheAndColorsTheme()->listCachedRectKeys(path);
|
||||
for (const QString &key : lst) {
|
||||
const auto match = sizeHintedKeyExpr.match(key);
|
||||
if (match.hasMatch()) {
|
||||
QString baseElementId = match.captured(3);
|
||||
QSize sizeHint(match.capturedRef(1).toInt(),
|
||||
match.capturedRef(2).toInt());
|
||||
if (sizeHint.isValid()) {
|
||||
elementsWithSizeHints.insert(baseElementId, sizeHint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (elementsWithSizeHints.isEmpty()) {
|
||||
// Make sure we won't query the theme unnecessarily.
|
||||
elementsWithSizeHints.insert(QString(), QSize());
|
||||
}
|
||||
}
|
||||
|
||||
// Look at the size hinted elements and try to find the smallest one with an
|
||||
// identical aspect ratio.
|
||||
if (s.isValid() && !elementId.isEmpty()) {
|
||||
const QList<QSize> elementSizeHints = elementsWithSizeHints.values(elementId);
|
||||
const QList<QSize> elementSizeHints = SvgRectsCache::instance()->sizeHintsForId(path, elementId);
|
||||
|
||||
if (!elementSizeHints.isEmpty()) {
|
||||
QSize bestFit(-1, -1);
|
||||
QSizeF bestFit(-1, -1);
|
||||
|
||||
for (const QSize &hint : elementSizeHints) {
|
||||
for (const auto &hint : elementSizeHints) {
|
||||
|
||||
if (hint.width() >= s.width() * ratio && hint.height() >= s.height() * ratio &&
|
||||
(!bestFit.isValid() ||
|
||||
@ -353,9 +561,7 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, qreal ratio, const QSi
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
const QString id = cachePath(path, size) + actualElementId;
|
||||
|
||||
//qCDebug(LOG_PLASMA) << "id is " << id;
|
||||
const QString id = cachePath(actualElementId, size);
|
||||
|
||||
QPixmap p;
|
||||
if (cacheRendering && cacheAndColorsTheme()->findInCache(id, p, lastModified)) {
|
||||
@ -364,11 +570,6 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, qreal ratio, const QSi
|
||||
return p;
|
||||
}
|
||||
|
||||
//qCDebug(LOG_PLASMA) << "didn't find cached version of " << id << ", so re-rendering";
|
||||
|
||||
//qCDebug(LOG_PLASMA) << "size for " << actualElementId << " is " << s;
|
||||
// we have to re-render this puppy
|
||||
|
||||
createRenderer();
|
||||
|
||||
QRectF finalRect = makeUniform(renderer->boundsOnElement(actualElementId), QRect(QPoint(0, 0), size));
|
||||
@ -397,9 +598,11 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, qreal ratio, const QSi
|
||||
}
|
||||
|
||||
if (cacheRendering) {
|
||||
cacheAndColorsTheme()->insertIntoCache(id, p, QString::number((qint64)q, 16) % QLSEP % actualElementId);
|
||||
cacheAndColorsTheme()->insertIntoCache(id, p, QString::number((qint64)q, 16) % QLatin1Char('_') % actualElementId);
|
||||
}
|
||||
|
||||
SvgRectsCache::instance()->updateLastModified(path, lastModified);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -409,7 +612,6 @@ void SvgPrivate::createRenderer()
|
||||
return;
|
||||
}
|
||||
|
||||
//qCDebug(LOG_PLASMA) << kBacktrace();
|
||||
if (themed && path.isEmpty() && !themeFailed) {
|
||||
Applet *applet = qobject_cast<Applet *>(q->parent());
|
||||
//FIXME: this maybe could be more efficient if we knew if the package was empty, e.g. for
|
||||
@ -433,17 +635,12 @@ void SvgPrivate::createRenderer()
|
||||
}
|
||||
}
|
||||
|
||||
//qCDebug(LOG_PLASMA) << "********************************";
|
||||
//qCDebug(LOG_PLASMA) << "FAIL! **************************";
|
||||
//qCDebug(LOG_PLASMA) << path << "**";
|
||||
|
||||
QString styleSheet = cacheAndColorsTheme()->d->svgStyleSheet(colorGroup, status);
|
||||
styleCrc = qChecksum(styleSheet.toUtf8().constData(), styleSheet.size());
|
||||
|
||||
QHash<QString, SharedSvgRenderer::Ptr>::const_iterator it = s_renderers.constFind(styleCrc + path);
|
||||
|
||||
if (it != s_renderers.constEnd()) {
|
||||
//qCDebug(LOG_PLASMA) << "gots us an existing one!";
|
||||
renderer = it.value();
|
||||
} else {
|
||||
if (path.isEmpty()) {
|
||||
@ -455,14 +652,19 @@ void SvgPrivate::createRenderer()
|
||||
// Add interesting elements to the theme's rect cache.
|
||||
QHashIterator<QString, QRectF> i(interestingElements);
|
||||
|
||||
QRegularExpression sizeHintedKeyExpr(QStringLiteral("^(\\d+)-(\\d+)-(.+)$"));
|
||||
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
const QString &elementId = i.key();
|
||||
QString originalId = i.key();
|
||||
const QRectF &elementRect = i.value();
|
||||
|
||||
const QString cacheId = CACHE_ID_NATURAL_SIZE(elementId, status, devicePixelRatio);
|
||||
localRectCache.insert(cacheId, elementRect);
|
||||
cacheAndColorsTheme()->insertIntoRectsCache(path, cacheId, elementRect);
|
||||
originalId.replace(sizeHintedKeyExpr, QStringLiteral("\\3"));
|
||||
SvgRectsCache::instance()->insertSizeHintForId(path, originalId, elementRect.size().toSize());
|
||||
|
||||
const CacheId cacheId({-1.0, -1.0, path, elementId, status, devicePixelRatio, scaleFactor, -1, 0, lastModified});
|
||||
SvgRectsCache::instance()->insert(cacheId, elementRect, lastModified);
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,16 +686,10 @@ void SvgPrivate::eraseRenderer()
|
||||
#endif
|
||||
// this and the cache reference it
|
||||
s_renderers.erase(s_renderers.find(styleCrc + path));
|
||||
|
||||
if (theme) {
|
||||
theme.data()->releaseRectsCache(path);
|
||||
}
|
||||
}
|
||||
|
||||
renderer = nullptr;
|
||||
styleCrc = 0;
|
||||
localRectCache.clear();
|
||||
elementsWithSizeHints.clear();
|
||||
}
|
||||
|
||||
QRectF SvgPrivate::elementRect(const QString &elementId)
|
||||
@ -515,35 +711,23 @@ QRectF SvgPrivate::elementRect(const QString &elementId)
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
const QString id = cacheId(elementId);
|
||||
const auto it = localRectCache.constFind(id);
|
||||
if (it != localRectCache.constEnd()) {
|
||||
return *it;
|
||||
}
|
||||
|
||||
QRectF rect;
|
||||
bool found = cacheAndColorsTheme()->findInRectsCache(path, id, rect);
|
||||
const CacheId cacheId = SvgPrivate::cacheId(elementId);
|
||||
bool found = SvgRectsCache::instance()->findElementRect(cacheId, rect);
|
||||
//This is a corner case where we are *sure* the element is not valid
|
||||
if (found && rect == QRectF()) {
|
||||
return rect;
|
||||
} else if (found) {
|
||||
localRectCache.insert(id, rect);
|
||||
} else {
|
||||
rect = findAndCacheElementRect(elementId, id);
|
||||
if (!found) {
|
||||
rect = findAndCacheElementRect(elementId);
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
QRectF SvgPrivate::findAndCacheElementRect(const QString &elementId, const QString &id)
|
||||
QRectF SvgPrivate::findAndCacheElementRect(const QString &elementId)
|
||||
{
|
||||
//we need to check the id before createRenderer(), otherwise it may generate a different id compared to the previous cacheId)( call
|
||||
createRenderer();
|
||||
const CacheId cacheId = SvgPrivate::cacheId(elementId);
|
||||
|
||||
const auto it = localRectCache.constFind(id);
|
||||
if (it != localRectCache.constEnd()) {
|
||||
return *it;
|
||||
}
|
||||
createRenderer();
|
||||
|
||||
//This code will usually never be run because createRenderer already caches all the boundingRect in the elements in the svg
|
||||
QRectF elementRect = renderer->elementExists(elementId) ?
|
||||
@ -560,9 +744,7 @@ QRectF SvgPrivate::findAndCacheElementRect(const QString &elementId, const QStri
|
||||
|
||||
elementRect = QRectF(elementRect.x() * dx, elementRect.y() * dy,
|
||||
elementRect.width() * dx, elementRect.height() * dy);
|
||||
|
||||
cacheAndColorsTheme()->insertIntoRectsCache(path, id, elementRect);
|
||||
localRectCache.insert(id, elementRect);
|
||||
SvgRectsCache::instance()->insert(cacheId, elementRect, lastModified);
|
||||
|
||||
return elementRect;
|
||||
}
|
||||
@ -642,7 +824,6 @@ QRectF SvgPrivate::makeUniform(const QRectF &orig, const QRectF &dst)
|
||||
res.setHeight(res.height() + offset);
|
||||
}
|
||||
|
||||
//qCDebug(LOG_PLASMA)<<"Aligning Rects, origin:"<<orig<<"destination:"<<dst<<"result:"<<res;
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -732,9 +913,8 @@ void Svg::setScaleFactor(qreal ratio)
|
||||
//not resize() because we want to do it unconditionally
|
||||
QRectF rect;
|
||||
|
||||
if (d->cacheAndColorsTheme()->findInRectsCache(d->path, QStringLiteral("_Natural_%1").arg(d->scaleFactor), rect)) {
|
||||
d->naturalSize = rect.size();
|
||||
} else {
|
||||
d->naturalSize = SvgRectsCache::instance()->naturalSize(d->path, d->scaleFactor);
|
||||
if (d->naturalSize.isEmpty()) {
|
||||
d->createRenderer();
|
||||
d->naturalSize = d->renderer->defaultSize() * d->scaleFactor;
|
||||
}
|
||||
@ -840,7 +1020,6 @@ void Svg::resize(const QSizeF &size)
|
||||
}
|
||||
|
||||
d->size = size;
|
||||
d->localRectCache.clear();
|
||||
emit sizeChanged();
|
||||
}
|
||||
|
||||
@ -852,7 +1031,6 @@ void Svg::resize()
|
||||
}
|
||||
|
||||
d->size = d->naturalSize;
|
||||
d->localRectCache.clear();
|
||||
emit sizeChanged();
|
||||
}
|
||||
|
||||
@ -883,14 +1061,14 @@ bool Svg::isValid() const
|
||||
|
||||
//try very hard to avoid creation of a parser
|
||||
QRectF rect;
|
||||
if (d->cacheAndColorsTheme()->findInRectsCache(d->path, QStringLiteral("_Natural_%1").arg(d->scaleFactor), rect)) {
|
||||
QSizeF naturalSize = SvgRectsCache::instance()->naturalSize(d->path, d->scaleFactor);
|
||||
if (!naturalSize.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (d->path.isEmpty() || !QFileInfo::exists(d->path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
d->createRenderer();
|
||||
return d->renderer->isValid();
|
||||
}
|
||||
@ -908,7 +1086,6 @@ bool Svg::containsMultipleImages() const
|
||||
void Svg::setImagePath(const QString &svgFilePath)
|
||||
{
|
||||
if (d->setImagePath(svgFilePath)) {
|
||||
//qCDebug(LOG_PLASMA) << "repaintNeeded";
|
||||
emit repaintNeeded();
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "theme.h"
|
||||
#include "private/theme_p.h"
|
||||
#include "private/svg_p.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QFontDatabase>
|
||||
@ -38,11 +39,11 @@ Theme::Theme(QObject *parent)
|
||||
{
|
||||
if (!ThemePrivate::globalTheme) {
|
||||
ThemePrivate::globalTheme = new ThemePrivate;
|
||||
ThemePrivate::globalTheme->settingsChanged(false);
|
||||
}
|
||||
ThemePrivate::globalTheme->ref.ref();
|
||||
d = ThemePrivate::globalTheme;
|
||||
|
||||
d->settingsChanged(false);
|
||||
if (QCoreApplication::instance()) {
|
||||
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
|
||||
d, &ThemePrivate::onAppExitCleanup);
|
||||
@ -335,36 +336,13 @@ bool Theme::findInRectsCache(const QString &image, const QString &element, QRect
|
||||
return false;
|
||||
}
|
||||
|
||||
KConfigGroup imageGroup(d->svgElementsCache, image);
|
||||
rect = imageGroup.readEntry(element % QLatin1String("Size"), QRectF());
|
||||
|
||||
if (rect.isValid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Name starting by _ means the element is empty and we're asked for the size of
|
||||
//the whole image, so the whole image is never invalid
|
||||
if (element.indexOf(QLatin1Char('_')) <= 0) {
|
||||
bool ok = false;
|
||||
uint id = element.toLong(&ok);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool invalid = false;
|
||||
|
||||
QHash<QString, QSet<QString> >::iterator it = d->invalidElements.find(image);
|
||||
if (it == d->invalidElements.end()) {
|
||||
const QStringList elementList = imageGroup.readEntry("invalidElements", QStringList());
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
const QSet<QString> elements(elementList.begin(), elementList.end());
|
||||
#else
|
||||
const QSet<QString> elements = elementList.toSet();
|
||||
#endif
|
||||
d->invalidElements.insert(image, elements);
|
||||
invalid = elements.contains(element);
|
||||
} else {
|
||||
invalid = it.value().contains(element);
|
||||
}
|
||||
|
||||
return invalid;
|
||||
return SvgRectsCache::instance()->findElementRect(id, image, rect);
|
||||
}
|
||||
|
||||
QStringList Theme::listCachedRectKeys(const QString &image) const
|
||||
@ -373,21 +351,7 @@ QStringList Theme::listCachedRectKeys(const QString &image) const
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
KConfigGroup imageGroup(d->svgElementsCache, image);
|
||||
QStringList keys = imageGroup.keyList();
|
||||
|
||||
QMutableListIterator<QString> i(keys);
|
||||
while (i.hasNext()) {
|
||||
QString key = i.next();
|
||||
if (key.endsWith(QLatin1String("Size"))) {
|
||||
// The actual cache id used from outside doesn't end on "Size".
|
||||
key.resize(key.size() - 4);
|
||||
i.setValue(key);
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
return SvgRectsCache::instance()->cachedKeysForPath(image);
|
||||
}
|
||||
|
||||
void Theme::insertIntoRectsCache(const QString &image, const QString &element, const QRectF &rect)
|
||||
@ -396,46 +360,26 @@ void Theme::insertIntoRectsCache(const QString &image, const QString &element, c
|
||||
return;
|
||||
}
|
||||
|
||||
if (rect.isValid()) {
|
||||
KConfigGroup imageGroup(d->svgElementsCache, image);
|
||||
imageGroup.writeEntry(element % QLatin1String("Size"), rect);
|
||||
} else {
|
||||
QHash<QString, QSet<QString> >::iterator it = d->invalidElements.find(image);
|
||||
if (it == d->invalidElements.end()) {
|
||||
d->invalidElements[image].insert(element);
|
||||
} else if (!it.value().contains(element)) {
|
||||
if (it.value().count() > 1000) {
|
||||
it.value().erase(it.value().begin());
|
||||
}
|
||||
|
||||
it.value().insert(element);
|
||||
}
|
||||
bool ok = false;
|
||||
uint id = element.toLong(&ok);
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(d->rectSaveTimer, "start");
|
||||
uint secs = QDateTime::currentSecsSinceEpoch();
|
||||
SvgRectsCache::instance()->insert(id, image, rect, secs);
|
||||
}
|
||||
|
||||
void Theme::invalidateRectsCache(const QString &image)
|
||||
{
|
||||
if (d->useCache()) {
|
||||
KConfigGroup imageGroup(d->svgElementsCache, image);
|
||||
imageGroup.deleteGroup();
|
||||
}
|
||||
|
||||
d->invalidElements.remove(image);
|
||||
|
||||
SvgRectsCache::instance()->dropImageFromCache(image);
|
||||
}
|
||||
|
||||
void Theme::releaseRectsCache(const QString &image)
|
||||
{
|
||||
QHash<QString, QSet<QString> >::iterator it = d->invalidElements.find(image);
|
||||
if (it != d->invalidElements.end()) {
|
||||
if (d->useCache()) {
|
||||
KConfigGroup imageGroup(d->svgElementsCache, it.key());
|
||||
imageGroup.writeEntry("invalidElements", it.value().values());
|
||||
}
|
||||
|
||||
d->invalidElements.erase(it);
|
||||
}
|
||||
Q_UNUSED(image);
|
||||
// No op: the internal svg cache always writes the invalid elements in the proper place
|
||||
}
|
||||
|
||||
void Theme::setCacheLimit(int kbytes)
|
||||
|
@ -270,6 +270,7 @@ public:
|
||||
**/
|
||||
void setCacheLimit(int kbytes);
|
||||
|
||||
#if PLASMA_ENABLE_DEPRECATED_SINCE(5, 78)
|
||||
/**
|
||||
* Tries to load the rect of a sub element from a disk cache
|
||||
*
|
||||
@ -279,6 +280,7 @@ public:
|
||||
* if not found or if we are sure it doesn't exist it will be QRect()
|
||||
* @return true if the element was found in cache or if we are sure the element doesn't exist
|
||||
**/
|
||||
PLASMA_DEPRECATED_VERSION(5, 78, "Rects Cache public API is deprecated")
|
||||
bool findInRectsCache(const QString &image, const QString &element, QRectF &rect) const;
|
||||
|
||||
/**
|
||||
@ -290,6 +292,7 @@ public:
|
||||
*
|
||||
* @since 4.6
|
||||
*/
|
||||
PLASMA_DEPRECATED_VERSION(5, 78, "Rects Cache public API is deprecated")
|
||||
QStringList listCachedRectKeys(const QString &image) const;
|
||||
|
||||
/**
|
||||
@ -299,6 +302,7 @@ public:
|
||||
* @param element sub element we want insert the rect
|
||||
* @param rect element rectangle
|
||||
**/
|
||||
PLASMA_DEPRECATED_VERSION(5, 78, "Rects Cache public API is deprecated")
|
||||
void insertIntoRectsCache(const QString &image, const QString &element, const QRectF &rect);
|
||||
|
||||
/**
|
||||
@ -306,6 +310,7 @@ public:
|
||||
*
|
||||
* @param image the path to the image the cache is associated with
|
||||
**/
|
||||
PLASMA_DEPRECATED_VERSION(5, 78, "Rects Cache public API is deprecated")
|
||||
void invalidateRectsCache(const QString &image);
|
||||
|
||||
/**
|
||||
@ -315,7 +320,9 @@ public:
|
||||
*
|
||||
* @param image the path to the image the cache is associated with
|
||||
*/
|
||||
PLASMA_DEPRECATED_VERSION(5, 78, "Rects Cache public API is deprecated")
|
||||
void releaseRectsCache(const QString &image);
|
||||
#endif
|
||||
|
||||
#if PLASMA_ENABLE_DEPRECATED_SINCE(5, 67)
|
||||
/**
|
||||
|
@ -46,6 +46,7 @@ target_link_libraries(KF5PlasmaQuick
|
||||
KF5::Plasma
|
||||
KF5::WindowSystem
|
||||
PRIVATE
|
||||
Qt5::Svg
|
||||
KF5::KIOWidgets
|
||||
KF5::I18n
|
||||
KF5::IconThemes
|
||||
|
Loading…
x
Reference in New Issue
Block a user