From cdba8f5621f5d68ff7764002077aded5be2e7b5a Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 3 Dec 2018 11:15:13 +1000 Subject: [PATCH] Use QgsAbstractContentCache base class for QgsSvgCache --- .../symbology/qgssvgcache.sip.in | 16 +- src/core/symbology/qgssvgcache.cpp | 372 +++--------------- src/core/symbology/qgssvgcache.h | 118 +----- 3 files changed, 89 insertions(+), 417 deletions(-) diff --git a/python/core/auto_generated/symbology/qgssvgcache.sip.in b/python/core/auto_generated/symbology/qgssvgcache.sip.in index f9ffb522aec..77f0bebfbfa 100644 --- a/python/core/auto_generated/symbology/qgssvgcache.sip.in +++ b/python/core/auto_generated/symbology/qgssvgcache.sip.in @@ -12,7 +12,7 @@ -class QgsSvgCache : QObject +class QgsSvgCache : QgsAbstractContentCacheBase { %Docstring A cache for images / pictures derived from svg files. This class supports parameter replacement in svg files @@ -33,8 +33,6 @@ QgsSvgCache is not usually directly created, but rather accessed through Constructor for QgsSvgCache. %End - ~QgsSvgCache(); - QImage svgAsImage( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio = 0 ); %Docstring @@ -135,9 +133,12 @@ Gets SVG content %End signals: - void statusChanged( const QString &statusQString ); + + void statusChanged( const QString &statusQString ) /Deprecated/; %Docstring -Emit a signal to be caught by qgisapp and display a msg on status bar +Emit a signal to be caught by qgisapp and display a msg on status bar. + +.. deprecated:: Deprecated since QGIS 3.6 -- no longer emitted. %End void remoteSvgFetched( const QString &url ); @@ -147,6 +148,11 @@ Emitted when the cache has finished retrieving an SVG file from a remote ``url`` .. versionadded:: 3.2 %End + protected: + + virtual bool checkReply( QNetworkReply *reply, const QString &path ) const; + + }; /************************************************************************ diff --git a/src/core/symbology/qgssvgcache.cpp b/src/core/symbology/qgssvgcache.cpp index 4e0bf0a5605..fe94f030777 100644 --- a/src/core/symbology/qgssvgcache.cpp +++ b/src/core/symbology/qgssvgcache.cpp @@ -39,28 +39,36 @@ ///@cond PRIVATE -QgsSvgCacheEntry::QgsSvgCacheEntry( const QString &p, double s, double ow, double wsf, const QColor &fi, const QColor &ou, double far ) - : path( p ) - , fileModified( QFileInfo( p ).lastModified() ) - , size( s ) - , strokeWidth( ow ) - , widthScaleFactor( wsf ) - , fixedAspectRatio( far ) - , fill( fi ) - , stroke( ou ) +// +// QgsSvgCacheEntry +// + +QgsSvgCacheEntry::QgsSvgCacheEntry( const QString &path, double size, double strokeWidth, double widthScaleFactor, const QColor &fill, const QColor &stroke, double fixedAspectRatio ) + : QgsAbstractContentCacheEntry( path ) + , size( size ) + , strokeWidth( strokeWidth ) + , widthScaleFactor( widthScaleFactor ) + , fixedAspectRatio( fixedAspectRatio ) + , fill( fill ) + , stroke( stroke ) { - fileModifiedLastCheckTimer.start(); } -bool QgsSvgCacheEntry::operator==( const QgsSvgCacheEntry &other ) const +bool QgsSvgCacheEntry::isEqual( const QgsAbstractContentCacheEntry *other ) const { - bool equal = other.path == path && qgsDoubleNear( other.size, size ) && qgsDoubleNear( other.strokeWidth, strokeWidth ) && qgsDoubleNear( other.widthScaleFactor, widthScaleFactor ) - && other.fixedAspectRatio == fixedAspectRatio && other.fill == fill && other.stroke == stroke; + const QgsSvgCacheEntry *otherSvg = dynamic_cast< const QgsSvgCacheEntry * >( other ); + // cheapest checks first! + if ( !otherSvg + || !qgsDoubleNear( otherSvg->fixedAspectRatio, fixedAspectRatio ) + || !qgsDoubleNear( otherSvg->size, size ) + || !qgsDoubleNear( otherSvg->strokeWidth, strokeWidth ) + || !qgsDoubleNear( otherSvg->widthScaleFactor, widthScaleFactor ) + || otherSvg->fill != fill + || otherSvg->stroke != stroke + || otherSvg->path != path ) + return false; - if ( equal && ( mFileModifiedCheckTimeout <= 0 || fileModifiedLastCheckTimer.hasExpired( mFileModifiedCheckTimeout ) ) ) - equal = other.fileModified == fileModified; - - return equal; + return true; } int QgsSvgCacheEntry::dataSize() const @@ -76,12 +84,20 @@ int QgsSvgCacheEntry::dataSize() const } return size; } + +void QgsSvgCacheEntry::dump() const +{ + QgsDebugMsg( QStringLiteral( "path: %1, size %2, width scale factor %3" ).arg( path ).arg( size ).arg( widthScaleFactor ) ); +} ///@endcond +// +// QgsSvgCache +// + QgsSvgCache::QgsSvgCache( QObject *parent ) - : QObject( parent ) - , mMutex( QMutex::Recursive ) + : QgsAbstractContentCache< QgsSvgCacheEntry >( parent, QObject::tr( "SVG" ) ) { mMissingSvg = QStringLiteral( "?" ).toLatin1(); @@ -99,14 +115,10 @@ QgsSvgCache::QgsSvgCache( QObject *parent ) { mFetchingSvg = QStringLiteral( "?" ).toLatin1(); } -} -QgsSvgCache::~QgsSvgCache() -{ - qDeleteAll( mEntryLookup ); + connect( this, &QgsAbstractContentCacheBase::remoteContentFetched, this, &QgsSvgCache::remoteSvgFetched ); } - QImage QgsSvgCache::svgAsImage( const QString &file, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, bool &fitsInCache, double fixedAspectRatio ) { @@ -138,7 +150,7 @@ QImage QgsSvgCache::svgAsImage( const QString &file, double size, const QColor & long cachedDataSize = 0; cachedDataSize += currentEntry->svgContent.size(); cachedDataSize += static_cast< int >( currentEntry->size * currentEntry->size * hwRatio * 32 ); - if ( cachedDataSize > MAXIMUM_SIZE / 2 ) + if ( cachedDataSize > mMaxCacheSize / 2 ) { fitsInCache = false; currentEntry->image.reset(); @@ -206,40 +218,9 @@ QSizeF QgsSvgCache::svgViewboxSize( const QString &path, double size, const QCol QMutexLocker locker( &mMutex ); QgsSvgCacheEntry *currentEntry = cacheEntry( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio ); - return currentEntry->viewboxSize; } -QgsSvgCacheEntry *QgsSvgCache::insertSvg( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, - double widthScaleFactor, double fixedAspectRatio ) -{ - QgsSvgCacheEntry *entry = new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke, fixedAspectRatio ); - entry->mFileModifiedCheckTimeout = mFileModifiedCheckTimeout; - - replaceParamsAndCacheSvg( entry ); - - mEntryLookup.insert( path, entry ); - - //insert to most recent place in entry list - if ( !mMostRecentEntry ) //inserting first entry - { - mLeastRecentEntry = entry; - mMostRecentEntry = entry; - entry->previousEntry = nullptr; - entry->nextEntry = nullptr; - } - else - { - entry->previousEntry = mMostRecentEntry; - entry->nextEntry = nullptr; - mMostRecentEntry->nextEntry = entry; - mMostRecentEntry = entry; - } - - trimToMaximumSize(); - return entry; -} - void QgsSvgCache::containsParams( const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasStrokeParam, QColor &defaultStrokeColor, bool &hasStrokeWidthParam, double &defaultStrokeWidth ) const { @@ -285,7 +266,7 @@ void QgsSvgCache::containsParams( const QString &path, hasDefaultStrokeOpacity = false; QDomDocument svgDoc; - if ( !svgDoc.setContent( getImageData( path ) ) ) + if ( !svgDoc.setContent( getContent( path, mMissingSvg, mFetchingSvg ) ) ) { return; } @@ -306,7 +287,7 @@ void QgsSvgCache::replaceParamsAndCacheSvg( QgsSvgCacheEntry *entry ) } QDomDocument svgDoc; - if ( !svgDoc.setContent( getImageData( entry->path ) ) ) + if ( !svgDoc.setContent( getContent( entry->path, mMissingSvg, mFetchingSvg ) ) ) { return; } @@ -383,126 +364,24 @@ double QgsSvgCache::calcSizeScaleFactor( QgsSvgCacheEntry *entry, const QDomElem return 1.0; } + QByteArray QgsSvgCache::getImageData( const QString &path ) const { - // is it a path to local file? - QFile svgFile( path ); - if ( svgFile.exists() ) + return getContent( path, mMissingSvg, mFetchingSvg ); +}; + +bool QgsSvgCache::checkReply( QNetworkReply *reply, const QString &path ) const +{ + // we accept both real SVG mime types AND plain text types - because some sites + // (notably github) serve up svgs as raw text + QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString(); + if ( !contentType.startsWith( QLatin1String( "image/svg+xml" ), Qt::CaseInsensitive ) + && !contentType.startsWith( QLatin1String( "text/plain" ), Qt::CaseInsensitive ) ) { - if ( svgFile.open( QIODevice::ReadOnly ) ) - { - return svgFile.readAll(); - } - else - { - return mMissingSvg; - } + QgsMessageLog::logMessage( tr( "Unexpected MIME type %1 received for %2" ).arg( contentType, path ), tr( "SVG" ) ); + return false; } - - // maybe it's an embedded base64 string - if ( path.startsWith( QLatin1String( "base64:" ), Qt::CaseInsensitive ) ) - { - QByteArray base64 = path.mid( 7 ).toLocal8Bit(); // strip 'base64:' prefix - return QByteArray::fromBase64( base64, QByteArray::OmitTrailingEquals ); - } - - // maybe it's a url... - if ( !path.contains( QLatin1String( "://" ) ) ) // otherwise short, relative SVG paths might be considered URLs - { - return mMissingSvg; - } - - QUrl svgUrl( path ); - if ( !svgUrl.isValid() ) - { - return mMissingSvg; - } - - // check whether it's a url pointing to a local file - if ( svgUrl.scheme().compare( QLatin1String( "file" ), Qt::CaseInsensitive ) == 0 ) - { - svgFile.setFileName( svgUrl.toLocalFile() ); - if ( svgFile.exists() ) - { - if ( svgFile.open( QIODevice::ReadOnly ) ) - { - return svgFile.readAll(); - } - } - - // not found... - return mMissingSvg; - } - - QMutexLocker locker( &mMutex ); - - // already a request in progress for this url - if ( mPendingRemoteUrls.contains( path ) ) - return mFetchingSvg; - - if ( mRemoteContentCache.contains( path ) ) - { - // already fetched this content - phew. Just return what we already got. - return *mRemoteContentCache[ path ]; - } - - mPendingRemoteUrls.insert( path ); - //fire up task to fetch image in background - QNetworkRequest request( svgUrl ); - request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache ); - request.setAttribute( QNetworkRequest::CacheSaveControlAttribute, true ); - - QgsNetworkContentFetcherTask *task = new QgsNetworkContentFetcherTask( request ); - connect( task, &QgsNetworkContentFetcherTask::fetched, this, [this, task, path] - { - QMutexLocker locker( &mMutex ); - - QNetworkReply *reply = task->reply(); - if ( !reply ) - { - // canceled - QMetaObject::invokeMethod( const_cast< QgsSvgCache * >( this ), "onRemoteSvgFetched", Qt::QueuedConnection, Q_ARG( QString, path ), Q_ARG( bool, false ) ); - return; - } - - if ( reply->error() != QNetworkReply::NoError ) - { - QgsMessageLog::logMessage( tr( "SVG request failed [error: %1 - url: %2]" ).arg( reply->errorString(), path ), tr( "SVG" ) ); - return; - } - - bool ok = true; - - QVariant status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ); - if ( !status.isNull() && status.toInt() >= 400 ) - { - QVariant phrase = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ); - QgsMessageLog::logMessage( tr( "SVG request error [status: %1 - reason phrase: %2] for %3" ).arg( status.toInt() ).arg( phrase.toString(), path ), tr( "SVG" ) ); - mRemoteContentCache.insert( path, new QByteArray( mMissingSvg ) ); - ok = false; - } - - // we accept both real SVG mime types AND plain text types - because some sites - // (notably github) serve up svgs as raw text - QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString(); - if ( !contentType.startsWith( QLatin1String( "image/svg+xml" ), Qt::CaseInsensitive ) - && !contentType.startsWith( QLatin1String( "text/plain" ), Qt::CaseInsensitive ) ) - { - QgsMessageLog::logMessage( tr( "Unexpected MIME type %1 received for %2" ).arg( contentType, path ), tr( "SVG" ) ); - mRemoteContentCache.insert( path, new QByteArray( mMissingSvg ) ); - ok = false; - } - - if ( ok ) - { - // read the image data - mRemoteContentCache.insert( path, new QByteArray( reply->readAll() ) ); - } - QMetaObject::invokeMethod( const_cast< QgsSvgCache * >( this ), "onRemoteSvgFetched", Qt::QueuedConnection, Q_ARG( QString, path ), Q_ARG( bool, true ) ); - } ); - - QgsApplication::taskManager()->addTask( task ); - return mFetchingSvg; + return true; } void QgsSvgCache::cacheImage( QgsSvgCacheEntry *entry ) @@ -585,60 +464,17 @@ void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry, bool forceVectorOutput QgsSvgCacheEntry *QgsSvgCache::cacheEntry( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, double fixedAspectRatio ) { - //search entries in mEntryLookup - QgsSvgCacheEntry *currentEntry = nullptr; - QList entries = mEntryLookup.values( path ); - QDateTime modified; - QList::iterator entryIt = entries.begin(); - for ( ; entryIt != entries.end(); ++entryIt ) - { - QgsSvgCacheEntry *cacheEntry = *entryIt; - if ( qgsDoubleNear( cacheEntry->size, size ) && cacheEntry->fill == fill && cacheEntry->stroke == stroke && - qgsDoubleNear( cacheEntry->strokeWidth, strokeWidth ) && qgsDoubleNear( cacheEntry->widthScaleFactor, widthScaleFactor ) && - qgsDoubleNear( cacheEntry->fixedAspectRatio, fixedAspectRatio ) ) - { - if ( mFileModifiedCheckTimeout <= 0 || cacheEntry->fileModifiedLastCheckTimer.hasExpired( mFileModifiedCheckTimeout ) ) - { - if ( !modified.isValid() ) - modified = QFileInfo( path ).lastModified(); + QgsSvgCacheEntry *currentEntry = findExistingEntry( new QgsSvgCacheEntry( path, size, strokeWidth, widthScaleFactor, fill, stroke, fixedAspectRatio ) ); - if ( cacheEntry->fileModified != modified ) - continue; - } - currentEntry = cacheEntry; - break; - } - } - - //if not found: create new entry - //cache and replace params in svg content - if ( !currentEntry ) + if ( currentEntry->svgContent.isEmpty() ) { - currentEntry = insertSvg( path, size, fill, stroke, strokeWidth, widthScaleFactor, fixedAspectRatio ); + replaceParamsAndCacheSvg( currentEntry ); } - else - { - takeEntryFromList( currentEntry ); - if ( !mMostRecentEntry ) //list is empty - { - mMostRecentEntry = currentEntry; - mLeastRecentEntry = currentEntry; - } - else - { - mMostRecentEntry->nextEntry = currentEntry; - currentEntry->previousEntry = mMostRecentEntry; - currentEntry->nextEntry = nullptr; - mMostRecentEntry = currentEntry; - } - } - - //debugging - //printEntryList(); return currentEntry; } + void QgsSvgCache::replaceElemParams( QDomElement &elem, const QColor &fill, const QColor &stroke, double strokeWidth ) { if ( elem.isNull() ) @@ -905,27 +741,6 @@ void QgsSvgCache::containsElemParams( const QDomElement &elem, bool &hasFillPara } } -void QgsSvgCache::removeCacheEntry( const QString &s, QgsSvgCacheEntry *entry ) -{ - delete entry; - mEntryLookup.remove( s, entry ); -} - -void QgsSvgCache::printEntryList() -{ - QgsDebugMsg( QStringLiteral( "****************svg cache entry list*************************" ) ); - QgsDebugMsg( "Cache size: " + QString::number( mTotalSize ) ); - QgsSvgCacheEntry *entry = mLeastRecentEntry; - while ( entry ) - { - QgsDebugMsg( QStringLiteral( "***Entry:" ) ); - QgsDebugMsg( "File:" + entry->path ); - QgsDebugMsg( "Size:" + QString::number( entry->size ) ); - QgsDebugMsg( "Width scale factor" + QString::number( entry->widthScaleFactor ) ); - entry = entry->nextEntry; - } -} - QSize QgsSvgCache::sizeForImage( const QgsSvgCacheEntry &entry, QSizeF &viewBoxSize, QSizeF &scaledSize ) const { bool isFixedAR = entry.fixedAspectRatio > 0; @@ -973,76 +788,3 @@ QImage QgsSvgCache::imageFromCachedPicture( const QgsSvgCacheEntry &entry ) cons return image; } -void QgsSvgCache::trimToMaximumSize() -{ - //only one entry in cache - if ( mLeastRecentEntry == mMostRecentEntry ) - { - return; - } - QgsSvgCacheEntry *entry = mLeastRecentEntry; - while ( entry && ( mTotalSize > MAXIMUM_SIZE ) ) - { - QgsSvgCacheEntry *bkEntry = entry; - entry = entry->nextEntry; - - takeEntryFromList( bkEntry ); - mEntryLookup.remove( bkEntry->path, bkEntry ); - mTotalSize -= bkEntry->dataSize(); - delete bkEntry; - } -} - -void QgsSvgCache::takeEntryFromList( QgsSvgCacheEntry *entry ) -{ - if ( !entry ) - { - return; - } - - if ( entry->previousEntry ) - { - entry->previousEntry->nextEntry = entry->nextEntry; - } - else - { - mLeastRecentEntry = entry->nextEntry; - } - if ( entry->nextEntry ) - { - entry->nextEntry->previousEntry = entry->previousEntry; - } - else - { - mMostRecentEntry = entry->previousEntry; - } -} - -void QgsSvgCache::downloadProgress( qint64 bytesReceived, qint64 bytesTotal ) -{ - QString msg = tr( "%1 of %2 bytes of svg image downloaded." ).arg( bytesReceived ).arg( bytesTotal < 0 ? QStringLiteral( "unknown number of" ) : QString::number( bytesTotal ) ); - QgsDebugMsg( msg ); - emit statusChanged( msg ); -} - -void QgsSvgCache::onRemoteSvgFetched( const QString &url, bool success ) -{ - QMutexLocker locker( &mMutex ); - mPendingRemoteUrls.remove( url ); - - QgsSvgCacheEntry *nextEntry = mLeastRecentEntry; - while ( QgsSvgCacheEntry *entry = nextEntry ) - { - nextEntry = entry->nextEntry; - if ( entry->path == url ) - { - takeEntryFromList( entry ); - mEntryLookup.remove( entry->path, entry ); - mTotalSize -= entry->dataSize(); - delete entry; - } - } - - if ( success ) - emit remoteSvgFetched( url ); -} diff --git a/src/core/symbology/qgssvgcache.h b/src/core/symbology/qgssvgcache.h index 90b51bd7ddb..3c4ffa940c3 100644 --- a/src/core/symbology/qgssvgcache.h +++ b/src/core/symbology/qgssvgcache.h @@ -18,24 +18,12 @@ #ifndef QGSSVGCACHE_H #define QGSSVGCACHE_H -#include +#include "qgsabstractcontentcache.h" #include "qgis.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "qgis_core.h" +#include + class QDomElement; #ifndef SIP_RUN @@ -46,12 +34,10 @@ class QDomElement; * \ingroup core * \class QgsSvgCacheEntry */ -class CORE_EXPORT QgsSvgCacheEntry +class CORE_EXPORT QgsSvgCacheEntry : public QgsAbstractContentCacheEntry { public: - QgsSvgCacheEntry() = delete; - /** * Constructor. * \param path Absolute path to SVG file (relative paths are not resolved). @@ -70,15 +56,6 @@ class CORE_EXPORT QgsSvgCacheEntry //! QgsSvgCacheEntry cannot be copied. QgsSvgCacheEntry &operator=( const QgsSvgCacheEntry &rh ) = delete; - //! Absolute path to SVG file - QString path; - - //! Timestamp when file was last modified - QDateTime fileModified; - //! Time since last check of file modified date - QElapsedTimer fileModifiedLastCheckTimer; - int mFileModifiedCheckTimeout = 30000; - double size = 0.0; //size in pixels (cast to int for QImage) double strokeWidth = 0; double widthScaleFactor = 1.0; @@ -99,19 +76,9 @@ class CORE_EXPORT QgsSvgCacheEntry //content (with params replaced) QByteArray svgContent; - //keep entries on a least, sorted by last access - QgsSvgCacheEntry *nextEntry = nullptr; - QgsSvgCacheEntry *previousEntry = nullptr; - - //! Don't consider image, picture, last used timestamp for comparison - bool operator==( const QgsSvgCacheEntry &other ) const; - //! Returns memory usage in bytes - int dataSize() const; - - private: -#ifdef SIP_RUN - QgsSvgCacheEntry( const QgsSvgCacheEntry &rh ); -#endif + bool isEqual( const QgsAbstractContentCacheEntry *other ) const override; + int dataSize() const override; + void dump() const override; }; @@ -127,8 +94,13 @@ the parameters 'fill-color', 'pen-color', 'outline-width', 'stroke-width'. E.g. * QgsSvgCache is not usually directly created, but rather accessed through * QgsApplication::svgCache(). */ -class CORE_EXPORT QgsSvgCache : public QObject +#ifdef SIP_RUN +class CORE_EXPORT QgsSvgCache : public QgsAbstractContentCacheBase // for sip we skip to the base class and avoid the template difficulty { +#else +class CORE_EXPORT QgsSvgCache : public QgsAbstractContentCache< QgsSvgCacheEntry > +{ +#endif Q_OBJECT public: @@ -138,8 +110,6 @@ class CORE_EXPORT QgsSvgCache : public QObject */ QgsSvgCache( QObject *parent SIP_TRANSFERTHIS = nullptr ); - ~QgsSvgCache() override; - /** * Gets SVG as QImage. * \param path Absolute path to SVG file. @@ -225,8 +195,12 @@ class CORE_EXPORT QgsSvgCache : public QObject double widthScaleFactor, double fixedAspectRatio = 0 ); signals: - //! Emit a signal to be caught by qgisapp and display a msg on status bar - void statusChanged( const QString &statusQString ); + + /** + * Emit a signal to be caught by qgisapp and display a msg on status bar. + * \deprecated Deprecated since QGIS 3.6 -- no longer emitted. + */ + Q_DECL_DEPRECATED void statusChanged( const QString &statusQString ) SIP_DEPRECATED; /** * Emitted when the cache has finished retrieving an SVG file from a remote \a url. @@ -234,26 +208,12 @@ class CORE_EXPORT QgsSvgCache : public QObject */ void remoteSvgFetched( const QString &url ); - private slots: - void downloadProgress( qint64, qint64 ); + protected: - void onRemoteSvgFetched( const QString &url, bool success ); + bool checkReply( QNetworkReply *reply, const QString &path ) const override; private: - /** - * Creates new cache entry and returns pointer to it - * \param path Absolute path to SVG file - * \param size size of cached image - * \param fill color of fill - * \param stroke color of stroke - * \param strokeWidth width of stroke - * \param widthScaleFactor width scale factor - * \param fixedAspectRatio fixed aspect ratio (optional) - */ - QgsSvgCacheEntry *insertSvg( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, - double widthScaleFactor, double fixedAspectRatio = 0 ); - void replaceParamsAndCacheSvg( QgsSvgCacheEntry *entry ); void cacheImage( QgsSvgCacheEntry *entry ); void cachePicture( QgsSvgCacheEntry *entry, bool forceVectorOutput = false ); @@ -261,28 +221,6 @@ class CORE_EXPORT QgsSvgCache : public QObject QgsSvgCacheEntry *cacheEntry( const QString &path, double size, const QColor &fill, const QColor &stroke, double strokeWidth, double widthScaleFactor, double fixedAspectRatio = 0 ); - //! Removes the least used items until the maximum size is under the limit - void trimToMaximumSize(); - - //Removes entry from the ordered list (but does not delete the entry itself) - void takeEntryFromList( QgsSvgCacheEntry *entry ); - - //! Minimum time (in ms) between consecutive svg file modified time checks - int mFileModifiedCheckTimeout = 30000; - - //! Entry pointers accessible by file name - QMultiHash< QString, QgsSvgCacheEntry * > mEntryLookup; - //! Estimated total size of all images, pictures and svgContent - long mTotalSize = 0; - - //The svg cache keeps the entries on a double connected list, moving the current entry to the front. - //That way, removing entries for more space can start with the least used objects. - QgsSvgCacheEntry *mLeastRecentEntry = nullptr; - QgsSvgCacheEntry *mMostRecentEntry = nullptr; - - //! Maximum cache size - static const long MAXIMUM_SIZE = 20000000; - //! Replaces parameters in elements of a dom node and calls method for all child nodes void replaceElemParams( QDomElement &elem, const QColor &fill, const QColor &stroke, double strokeWidth ); @@ -296,12 +234,6 @@ class CORE_EXPORT QgsSvgCache : public QObject //! Calculates scaling for rendered image sizes to SVG logical sizes double calcSizeScaleFactor( QgsSvgCacheEntry *entry, const QDomElement &docElem, QSizeF &viewboxSize ) const; - //! Release memory and remove cache entry from mEntryLookup - void removeCacheEntry( const QString &s, QgsSvgCacheEntry *entry ); - - //! For debugging - void printEntryList(); - /** * Returns the target size (in pixels) and calculates the \a viewBoxSize * for a cache \a entry. @@ -313,19 +245,11 @@ class CORE_EXPORT QgsSvgCache : public QObject */ QImage imageFromCachedPicture( const QgsSvgCacheEntry &entry ) const; - QByteArray fetchImageData( const QString &path, bool &ok ) const; - //! SVG content to be rendered if SVG file was not found. QByteArray mMissingSvg; QByteArray mFetchingSvg; - //! Mutex to prevent concurrent access to the class from multiple threads at once (may corrupt the entries otherwise). - mutable QMutex mMutex; - - mutable QCache< QString, QByteArray > mRemoteContentCache; - mutable QSet< QString > mPendingRemoteUrls; - friend class TestQgsSvgCache; };