25 #include <QApplication>    26 #include <QCoreApplication>    28 #include <QDomDocument>    29 #include <QDomElement>    34 #include <QSvgRenderer>    36 #include <QNetworkReply>    37 #include <QNetworkRequest>    43     , widthScaleFactor( 1.0 )
    44     , rasterScaleFactor( 1.0 )
    46     , outline( 
Qt::black )
    49     , nextEntry( nullptr )
    50     , previousEntry( nullptr )
   106     , mLeastRecentEntry( nullptr )
   107     , mMostRecentEntry( nullptr )
   109   mMissingSvg = 
QString( 
"<svg width='10' height='10'><text x='5' y='10' font-size='10' text-anchor='middle'>?</text></svg>" ).
toAscii();
   114   qDeleteAll( mEntryLookup );
   119                                        double widthScaleFactor, 
double rasterScaleFactor, 
bool& fitsInCache )
   129   if ( !currentEntry->
image )
   132     double hwRatio = 1.0;
   137     long cachedDataSize = 0;
   139     cachedDataSize += 
static_cast< int >( currentEntry->
size * currentEntry->
size * hwRatio * 32 );
   140     if ( cachedDataSize > mMaximumSize / 2 )
   143       delete currentEntry->
image;
   144       currentEntry->
image = 
nullptr;
   160   return *( currentEntry->
image );
   164     double widthScaleFactor, 
double rasterScaleFactor, 
bool forceVectorOutput )
   178   return *( currentEntry->
picture );
   182     double widthScaleFactor, 
double rasterScaleFactor )
   201     double widthScaleFactor, 
double rasterScaleFactor )
   210   mEntryLookup.
insert( file, entry );
   213   if ( !mMostRecentEntry ) 
   215     mLeastRecentEntry = entry;
   216     mMostRecentEntry = entry;
   225     mMostRecentEntry = entry;
   233                                   bool& hasOutlineWidthParam, 
double& defaultOutlineWidth )
 const   235   bool hasDefaultFillColor = 
false;
   236   bool hasFillOpacityParam = 
false;
   237   bool hasDefaultFillOpacity = 
false;
   238   double defaultFillOpacity = 1.0;
   239   bool hasDefaultOutlineColor = 
false;
   240   bool hasDefaultOutlineWidth = 
false;
   241   bool hasOutlineOpacityParam = 
false;
   242   bool hasDefaultOutlineOpacity = 
false;
   243   double defaultOutlineOpacity = 1.0;
   245   containsParams( path, hasFillParam, hasDefaultFillColor, defaultFillColor,
   246                   hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
   247                   hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
   248                   hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
   249                   hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
   254                                   bool& hasFillParam, 
bool& hasDefaultFillParam, 
QColor& defaultFillColor,
   255                                   bool& hasOutlineParam, 
bool& hasDefaultOutlineColor, 
QColor& defaultOutlineColor,
   256                                   bool& hasOutlineWidthParam, 
bool& hasDefaultOutlineWidth, 
double& defaultOutlineWidth )
 const   258   bool hasFillOpacityParam = 
false;
   259   bool hasDefaultFillOpacity = 
false;
   260   double defaultFillOpacity = 1.0;
   261   bool hasOutlineOpacityParam = 
false;
   262   bool hasDefaultOutlineOpacity = 
false;
   263   double defaultOutlineOpacity = 1.0;
   265   containsParams( path, hasFillParam, hasDefaultFillParam, defaultFillColor,
   266                   hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
   267                   hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
   268                   hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
   269                   hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
   273                                   bool& hasFillParam, 
bool& hasDefaultFillParam, 
QColor& defaultFillColor,
   274                                   bool& hasFillOpacityParam, 
bool& hasDefaultFillOpacity, 
double& defaultFillOpacity,
   275                                   bool& hasOutlineParam, 
bool& hasDefaultOutlineColor, 
QColor& defaultOutlineColor,
   276                                   bool& hasOutlineWidthParam, 
bool& hasDefaultOutlineWidth, 
double& defaultOutlineWidth,
   277                                   bool& hasOutlineOpacityParam, 
bool& hasDefaultOutlineOpacity, 
double& defaultOutlineOpacity )
 const   279   hasFillParam = 
false;
   280   hasFillOpacityParam = 
false;
   281   hasOutlineParam = 
false;
   282   hasOutlineWidthParam = 
false;
   283   hasOutlineOpacityParam = 
false;
   284   defaultFillColor = 
QColor( Qt::white );
   285   defaultFillOpacity = 1.0;
   286   defaultOutlineColor = 
QColor( Qt::black );
   287   defaultOutlineWidth = 0.2;
   288   defaultOutlineOpacity = 1.0;
   290   hasDefaultFillParam = 
false;
   291   hasDefaultFillOpacity = 
false;
   292   hasDefaultOutlineColor = 
false;
   293   hasDefaultOutlineWidth = 
false;
   294   hasDefaultOutlineOpacity = 
false;
   303   containsElemParams( docElem, hasFillParam, hasDefaultFillParam, defaultFillColor,
   304                       hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
   305                       hasOutlineParam, hasDefaultOutlineColor, defaultOutlineColor,
   306                       hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
   307                       hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
   327   double sizeScaleFactor = calcSizeScaleFactor( entry, docElem, viewboxSize );
   377   if ( parts.
count() != 4 )
   380   bool heightOk = 
false;
   381   double height = parts.
at( 3 ).toDouble( &heightOk );
   383   bool widthOk = 
false;
   384   double width = parts.
at( 2 ).toDouble( &widthOk );
   388       viewboxSize = 
QSizeF( width, height );
   389     return width / entry->
size;
   398   QFile svgFile( path );
   401     if ( svgFile.
open( QIODevice::ReadOnly ) )
   424   if ( svgUrl.
scheme().
compare( 
"file", Qt::CaseInsensitive ) == 0 )
   429       if ( svgFile.
open( QIODevice::ReadOnly ) )
   449     request.
setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache );
   450     request.
setAttribute( QNetworkRequest::CacheSaveControlAttribute, 
true );
   453     connect( reply, SIGNAL( downloadProgress( qint64, qint64 ) ), 
this, SLOT( downloadProgress( qint64, qint64 ) ) );
   464     if ( reply->
error() != QNetworkReply::NoError )
   472     QVariant redirect = reply->
attribute( QNetworkRequest::RedirectionTargetAttribute );
   481     svgUrl = redirect.
toUrl();
   488     QVariant phrase = reply->
attribute( QNetworkRequest::HttpReasonPhraseAttribute );
   497   if ( !contentType.
startsWith( 
"image/svg+xml", Qt::CaseInsensitive ) )
   518   entry->
image = 
nullptr;
   521   double hwRatio = 1.0;
   526   double wSize = entry->
size;
   527   int wImgSize = 
static_cast< int >( wSize );
   532   double hSize = wSize * hwRatio;
   533   int hImgSize = 
static_cast< int >( hSize );
   539   QImage* image = 
new QImage( wImgSize, hImgSize, QImage::Format_ARGB32_Premultiplied );
   550     s.
scale( wSize, hSize, Qt::KeepAspectRatio );
   551     QRectF rect(( wImgSize - s.width() ) / 2, ( hImgSize - s.height() ) / 2, s.width(), s.height() );
   555   entry->
image = image;
   556   mTotalSize += ( image->
width() * image->
height() * 32 );
   561   Q_UNUSED( forceVectorOutput );
   574   double hwRatio = 1.0;
   580   double wSize = entry->
size;
   581   double hSize = wSize * hwRatio;
   583   s.
scale( wSize, hSize, Qt::KeepAspectRatio );
   584   rect = 
QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() );
   593     double widthScaleFactor, 
double rasterScaleFactor )
   600   for ( ; entryIt != entries.
end(); ++entryIt )
   616     currentEntry = 
insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor );
   621     if ( !mMostRecentEntry ) 
   623       mMostRecentEntry = currentEntry;
   624       mLeastRecentEntry = currentEntry;
   628       mMostRecentEntry->
nextEntry = currentEntry;
   631       mMostRecentEntry = currentEntry;
   641 void QgsSvgCache::replaceElemParams( 
QDomElement& elem, 
const QColor& fill, 
const QColor& outline, 
double outlineWidth )
   650   int nAttributes = attributes.
count();
   651   for ( 
int i = 0; i < nAttributes; ++i )
   655     if ( attribute.
name().
compare( 
"style", Qt::CaseInsensitive ) == 0 )
   662       for ( ; entryIt != entryList.
constEnd(); ++entryIt )
   665         if ( keyValueSplit.
size() < 2 )
   675         else if ( value.
startsWith( 
"param(fill-opacity)" ) )
   679         else if ( value.
startsWith( 
"param(outline)" ) )
   681           value = outline.
name();
   683         else if ( value.
startsWith( 
"param(outline-opacity)" ) )
   687         else if ( value.
startsWith( 
"param(outline-width)" ) )
   694           newAttributeString.
append( 
';' );
   696         newAttributeString.
append( key + 
':' + value );
   707       else if ( value.
startsWith( 
"param(fill-opacity)" ) )
   711       else if ( value.
startsWith( 
"param(outline)" ) )
   715       else if ( value.
startsWith( 
"param(outline-opacity)" ) )
   719       else if ( value.
startsWith( 
"param(outline-width)" ) )
   727   int nChildren = childList.
count();
   728   for ( 
int i = 0; i < nChildren; ++i )
   731     replaceElemParams( childElem, fill, outline, outlineWidth );
   735 void QgsSvgCache::containsElemParams( 
const QDomElement& elem, 
bool& hasFillParam, 
bool& hasDefaultFill, 
QColor& defaultFill,
   736                                       bool& hasFillOpacityParam, 
bool& hasDefaultFillOpacity, 
double& defaultFillOpacity,
   737                                       bool& hasOutlineParam, 
bool& hasDefaultOutline, 
QColor& defaultOutline,
   738                                       bool& hasOutlineWidthParam, 
bool& hasDefaultOutlineWidth, 
double& defaultOutlineWidth,
   739                                       bool& hasOutlineOpacityParam, 
bool& hasDefaultOutlineOpacity, 
double& defaultOutlineOpacity )
 const   747   if ( hasFillParam && hasOutlineParam && hasOutlineWidthParam && hasFillOpacityParam && hasOutlineOpacityParam )
   754   int nAttributes = attributes.
count();
   757   for ( 
int i = 0; i < nAttributes; ++i )
   760     if ( attribute.
name().
compare( 
"style", Qt::CaseInsensitive ) == 0 )
   765       for ( ; entryIt != entryList.
constEnd(); ++entryIt )
   768         if ( keyValueSplit.
size() < 2 )
   773         valueSplit = value.
split( 
' ' );
   774         if ( !hasFillParam && value.
startsWith( 
"param(fill)" ) )
   777           if ( valueSplit.
size() > 1 )
   779             defaultFill = 
QColor( valueSplit.
at( 1 ) );
   780             hasDefaultFill = 
true;
   783         else if ( !hasFillOpacityParam && value.
startsWith( 
"param(fill-opacity)" ) )
   785           hasFillOpacityParam = 
true;
   786           if ( valueSplit.
size() > 1 )
   789             double opacity = valueSplit.
at( 1 ).toDouble( &ok );
   792               defaultFillOpacity = opacity;
   793               hasDefaultFillOpacity = 
true;
   797         else if ( !hasOutlineParam && value.
startsWith( 
"param(outline)" ) )
   799           hasOutlineParam = 
true;
   800           if ( valueSplit.
size() > 1 )
   802             defaultOutline = 
QColor( valueSplit.
at( 1 ) );
   803             hasDefaultOutline = 
true;
   806         else if ( !hasOutlineWidthParam && value.
startsWith( 
"param(outline-width)" ) )
   808           hasOutlineWidthParam = 
true;
   809           if ( valueSplit.
size() > 1 )
   811             defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
   812             hasDefaultOutlineWidth = 
true;
   815         else if ( !hasOutlineOpacityParam && value.
startsWith( 
"param(outline-opacity)" ) )
   817           hasOutlineOpacityParam = 
true;
   818           if ( valueSplit.
size() > 1 )
   821             double opacity = valueSplit.
at( 1 ).toDouble( &ok );
   824               defaultOutlineOpacity = opacity;
   825               hasDefaultOutlineOpacity = 
true;
   834       valueSplit = value.
split( 
' ' );
   835       if ( !hasFillParam && value.
startsWith( 
"param(fill)" ) )
   838         if ( valueSplit.
size() > 1 )
   840           defaultFill = 
QColor( valueSplit.
at( 1 ) );
   841           hasDefaultFill = 
true;
   844       else if ( !hasFillOpacityParam && value.
startsWith( 
"param(fill-opacity)" ) )
   846         hasFillOpacityParam = 
true;
   847         if ( valueSplit.
size() > 1 )
   850           double opacity = valueSplit.
at( 1 ).toDouble( &ok );
   853             defaultFillOpacity = opacity;
   854             hasDefaultFillOpacity = 
true;
   858       else if ( !hasOutlineParam && value.
startsWith( 
"param(outline)" ) )
   860         hasOutlineParam = 
true;
   861         if ( valueSplit.
size() > 1 )
   863           defaultOutline = 
QColor( valueSplit.
at( 1 ) );
   864           hasDefaultOutline = 
true;
   867       else if ( !hasOutlineWidthParam && value.
startsWith( 
"param(outline-width)" ) )
   869         hasOutlineWidthParam = 
true;
   870         if ( valueSplit.
size() > 1 )
   872           defaultOutlineWidth = valueSplit.
at( 1 ).toDouble();
   873           hasDefaultOutlineWidth = 
true;
   876       else if ( !hasOutlineOpacityParam && value.
startsWith( 
"param(outline-opacity)" ) )
   878         hasOutlineOpacityParam = 
true;
   879         if ( valueSplit.
size() > 1 )
   882           double opacity = valueSplit.
at( 1 ).toDouble( &ok );
   885             defaultOutlineOpacity = opacity;
   886             hasDefaultOutlineOpacity = 
true;
   895   int nChildren = childList.
count();
   896   for ( 
int i = 0; i < nChildren; ++i )
   899     containsElemParams( childElem, hasFillParam, hasDefaultFill, defaultFill,
   900                         hasFillOpacityParam, hasDefaultFillOpacity, defaultFillOpacity,
   901                         hasOutlineParam, hasDefaultOutline, defaultOutline,
   902                         hasOutlineWidthParam, hasDefaultOutlineWidth, defaultOutlineWidth,
   903                         hasOutlineOpacityParam, hasDefaultOutlineOpacity, defaultOutlineOpacity );
   910   mEntryLookup.
remove( s, entry );
   913 void QgsSvgCache::printEntryList()
   915   QgsDebugMsg( 
"****************svg cache entry list*************************" );
   932   if ( mLeastRecentEntry == mMostRecentEntry )
   937   while ( entry && ( mTotalSize > mMaximumSize ) )
   974 void QgsSvgCache::downloadProgress( qint64 bytesReceived, qint64 bytesTotal )
 
QgsSvgCacheEntry * previousEntry
QString & append(QChar ch)
QSizeF viewboxSize
SVG viewbox size. 
void scale(qreal width, qreal height, Qt::AspectRatioMode mode)
QByteArray getImageData(const QString &path) const
Get image data. 
void render(QPainter *painter)
const QPicture & svgAsPicture(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool forceVectorOutput=false)
Get SVG as QPicture&. 
QSizeF svgViewboxSize(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Calculates the viewbox size of a (possibly cached) SVG file. 
QString attribute(const QString &name, const QString &defValue) const
QString errorString() const
QgsSvgCacheEntry * cacheEntry(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Returns entry from cache or creates a new entry if it does not exist already. 
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
const T & at(int i) const
A cache for images / pictures derived from svg files. 
void setFileName(const QString &name)
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasOutlineParam, QColor &defaultOutlineColor, bool &hasOutlineWidthParam, double &defaultOutlineWidth) const
Tests if an svg file contains parameters for fill, outline color, outline width. 
QDomElement documentElement() const
QDomNodeList childNodes() const
QString toString(QFlags< QUrl::FormattingOption > options) const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference) 
static QgsSvgCache * instance()
QDomElement toElement() const
const QImage & svgAsImage(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool &fitsInCache)
Get SVG as QImage. 
int dataSize() const
Return memory usage in bytes. 
QString number(int n, int base)
int count(const T &value) const
void processEvents(QFlags< QEventLoop::ProcessEventsFlag > flags)
int toInt(bool *ok) const
void fill(uint pixelValue)
bool hasAttribute(const QString &name) const
void setAttribute(const QString &name, const QString &value)
int remove(const Key &key)
static QString symbolNameToPath(QString name)
Get symbol's path from its name. 
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
QByteArray & replace(int pos, int len, const char *after)
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary) 
void statusChanged(const QString &theStatusQString)
Emit a signal to be caught by qgisapp and display a msg on status bar. 
QgsSvgCache(QObject *parent=nullptr)
protected constructor 
const QByteArray & svgContent(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Get SVG content. 
void cachePicture(QgsSvgCacheEntry *entry, bool forceVectorOutput=false)
QHash< Key, T >::iterator insert(const Key &key, const T &value)
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QString toLocalFile() const
bool contains(QChar ch, Qt::CaseSensitivity cs) const
void trimToMaximumSize()
Removes the least used items until the maximum size is under the limit. 
void takeEntryFromList(QgsSvgCacheEntry *entry)
QString lookupKey
Lookup key used by QgsSvgCache's hashtable (relative or absolute path). Needed for removal from the h...
void cacheImage(QgsSvgCacheEntry *entry)
void replaceParamsAndCacheSvg(QgsSvgCacheEntry *entry)
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance 
QDomElement firstChildElement(const QString &tagName) const
QVariant attribute(QNetworkRequest::Attribute code) const
void setAttribute(Attribute code, const QVariant &value)
QgsSvgCacheEntry * insertSVG(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor)
Creates new cache entry and returns pointer to it. 
NetworkError error() const
QNetworkReply * get(const QNetworkRequest &request)
const_iterator constEnd() const
const_iterator constBegin() const
QDomNode item(int index) const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int compare(const QString &other) const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
bool operator==(const QgsSvgCacheEntry &other) const
Don't consider image, picture, last used timestamp for comparison. 
QString file
Absolute path to SVG file. 
QByteArray toAscii() const
QByteArray toByteArray(int indent) const
QDomNode at(int index) const
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
QgsSvgCacheEntry * nextEntry
QDomNamedNodeMap attributes() const