Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsvgiconengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qsvgiconengine.h"
4
5#ifndef QT_NO_SVGRENDERER
6
7#include "qpainter.h"
8#include "qpixmap.h"
9#include "qsvgrenderer.h"
10#include "qpixmapcache.h"
11#include "qfileinfo.h"
12#if QT_CONFIG(mimetype)
13#include <qmimedatabase.h>
14#include <qmimetype.h>
15#endif
16#include <QAtomicInt>
17#include "qdebug.h"
18#include <private/qguiapplication_p.h>
19
21
23{
24public:
28
31
33 { return (((mode)<<4)|state); }
34
36 { return QLatin1String("$qt_svgicon_")
37 + QString::number(serialNum, 16).append(QLatin1Char('_'))
38 + QString::number((((((qint64(size.width()) << 11) | size.height()) << 11) | mode) << 4) | state, 16); }
39
41 { serialNum = lastSerialNum.fetchAndAddRelaxed(1); }
42
45
46 QHash<int, QString> svgFiles;
47 QHash<int, QByteArray> *svgBuffers;
48 QHash<int, QPixmap> *addedPixmaps;
51};
52
54
59
62{
63 d->svgFiles = other.d->svgFiles;
64 if (other.d->svgBuffers)
65 d->svgBuffers = new QHash<int, QByteArray>(*other.d->svgBuffers);
66 if (other.d->addedPixmaps)
67 d->addedPixmaps = new QHash<int, QPixmap>(*other.d->addedPixmaps);
68}
69
70
74
75
78{
79 if (d->addedPixmaps) {
81 if (!pm.isNull() && pm.size() == size)
82 return size;
83 }
84
86 if (pm.isNull())
87 return QSize();
88 return pm.size();
89}
90
92{
93#ifndef QT_NO_COMPRESS
94 return qUncompress(ba);
95#else
96 return ba;
97#endif
98}
99
101{
102 if (svgBuffers) {
104 if (!buf.isEmpty()) {
106 renderer->load(buf);
107 return true;
108 }
109 }
110 QString svgFile = svgFiles.value(hashKey(mode, state));
111 if (!svgFile.isEmpty()) {
112 renderer->load(svgFile);
113 return true;
114 }
115 return false;
116}
117
119{
120 if (tryLoad(renderer, mode, state))
121 return mode;
122
123 const QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off : QIcon::On;
125 const QIcon::Mode oppositeMode = (mode == QIcon::Disabled) ? QIcon::Selected : QIcon::Disabled;
127 return QIcon::Normal;
129 return QIcon::Active;
130 if (tryLoad(renderer, mode, oppositeState))
131 return mode;
132 if (tryLoad(renderer, QIcon::Normal, oppositeState))
133 return QIcon::Normal;
134 if (tryLoad(renderer, QIcon::Active, oppositeState))
135 return QIcon::Active;
136 if (tryLoad(renderer, oppositeMode, state))
137 return oppositeMode;
138 if (tryLoad(renderer, oppositeMode, oppositeState))
139 return oppositeMode;
140 } else {
141 const QIcon::Mode oppositeMode = (mode == QIcon::Normal) ? QIcon::Active : QIcon::Normal;
142 if (tryLoad(renderer, oppositeMode, state))
143 return oppositeMode;
144 if (tryLoad(renderer, mode, oppositeState))
145 return mode;
146 if (tryLoad(renderer, oppositeMode, oppositeState))
147 return oppositeMode;
149 return QIcon::Disabled;
151 return QIcon::Selected;
152 if (tryLoad(renderer, QIcon::Disabled, oppositeState))
153 return QIcon::Disabled;
154 if (tryLoad(renderer, QIcon::Selected, oppositeState))
155 return QIcon::Selected;
156 }
157 return QIcon::Normal;
158}
159
162{
163 QPixmap pm;
164
165 QString pmckey(d->pmcKey(size, mode, state));
166 if (QPixmapCache::find(pmckey, &pm))
167 return pm;
168
169 if (d->addedPixmaps) {
170 pm = d->addedPixmaps->value(d->hashKey(mode, state));
171 if (!pm.isNull() && pm.size() == size)
172 return pm;
173 }
174
176 const QIcon::Mode loadmode = d->loadDataForModeAndState(&renderer, mode, state);
177 if (!renderer.isValid())
178 return pm;
179
181 if (!actualSize.isNull())
183
184 if (actualSize.isEmpty())
185 return QPixmap();
186
188 img.fill(0x00000000);
189 QPainter p(&img);
190 renderer.render(&p);
191 p.end();
193 if (qobject_cast<QGuiApplication *>(QCoreApplication::instance())) {
194 if (loadmode != mode && mode != QIcon::Normal) {
195 const QPixmap generated = QGuiApplicationPrivate::instance()->applyQIconStyleHelper(mode, pm);
196 if (!generated.isNull())
197 pm = generated;
198 }
199 }
200
201 if (!pm.isNull())
202 QPixmapCache::insert(pmckey, pm);
203
204 return pm;
205}
206
207
210{
211 if (!d->addedPixmaps)
212 d->addedPixmaps = new QHash<int, QPixmap>;
213 d->stepSerialNum();
215}
216
218
219static FileType fileType(const QFileInfo &fi)
220{
221 const QString &abs = fi.absoluteFilePath();
222 if (abs.endsWith(QLatin1String(".svg"), Qt::CaseInsensitive))
223 return SvgFile;
224 if (abs.endsWith(QLatin1String(".svgz"), Qt::CaseInsensitive)
225 || abs.endsWith(QLatin1String(".svg.gz"), Qt::CaseInsensitive)) {
226 return CompressedSvgFile;
227 }
228#if QT_CONFIG(mimetype)
229 const QString &mimeTypeName = QMimeDatabase().mimeTypeForFile(fi).name();
230 if (mimeTypeName == QLatin1String("image/svg+xml"))
231 return SvgFile;
232 if (mimeTypeName == QLatin1String("image/svg+xml-compressed"))
233 return CompressedSvgFile;
234#endif
235 return OtherFile;
236}
237
240{
241 if (!fileName.isEmpty()) {
242 const QFileInfo fi(fileName);
243 const QString abs = fi.absoluteFilePath();
244 const FileType type = fileType(fi);
245#ifndef QT_NO_COMPRESS
246 if (type == SvgFile || type == CompressedSvgFile) {
247#else
248 if (type == SvgFile) {
249#endif
251 if (renderer.isValid()) {
252 d->stepSerialNum();
253 d->svgFiles.insert(d->hashKey(mode, state), abs);
254 }
255 } else if (type == OtherFile) {
256 QPixmap pm(abs);
257 if (!pm.isNull())
258 addPixmap(pm, mode, state);
259 }
260 }
261}
262
265{
266 QSize pixmapSize = rect.size();
267 if (painter->device())
268 pixmapSize *= painter->device()->devicePixelRatio();
269 painter->drawPixmap(rect, pixmap(pixmapSize, mode, state));
270}
271
273{
274 return QLatin1String("svg");
275}
276
278{
279 return new QSvgIconEngine(*this);
280}
281
282
284{
285 d = new QSvgIconEnginePrivate;
286 d->svgBuffers = new QHash<int, QByteArray>;
287
288 if (in.version() >= QDataStream::Qt_4_4) {
289 int isCompressed;
290 QHash<int, QString> fileNames; // For memoryoptimization later
291 in >> fileNames >> isCompressed >> *d->svgBuffers;
292#ifndef QT_NO_COMPRESS
293 if (!isCompressed) {
294 for (auto it = d->svgBuffers->begin(), end = d->svgBuffers->end(); it != end; ++it)
295 it.value() = qCompress(it.value());
296 }
297#else
298 if (isCompressed) {
299 qWarning("QSvgIconEngine: Can not decompress SVG data");
300 d->svgBuffers->clear();
301 }
302#endif
303 int hasAddedPixmaps;
304 in >> hasAddedPixmaps;
305 if (hasAddedPixmaps) {
306 d->addedPixmaps = new QHash<int, QPixmap>;
307 in >> *d->addedPixmaps;
308 }
309 }
310 else {
313 uint mode;
314 uint state;
315 int num_entries;
316
317 in >> data;
318 if (!data.isEmpty()) {
319#ifndef QT_NO_COMPRESS
321#endif
322 if (!data.isEmpty())
324 }
325 in >> num_entries;
326 for (int i=0; i<num_entries; ++i) {
327 if (in.atEnd())
328 return false;
329 in >> pixmap;
330 in >> mode;
331 in >> state;
332 // The pm list written by 4.3 is buggy and/or useless, so ignore.
333 //addPixmap(pixmap, QIcon::Mode(mode), QIcon::State(state));
334 }
335 }
336
337 return true;
338}
339
340
342{
343 if (out.version() >= QDataStream::Qt_4_4) {
344 int isCompressed = 0;
345#ifndef QT_NO_COMPRESS
346 isCompressed = 1;
347#endif
348 QHash<int, QByteArray> svgBuffers;
349 if (d->svgBuffers)
350 svgBuffers = *d->svgBuffers;
351 for (auto it = d->svgFiles.cbegin(), end = d->svgFiles.cend(); it != end; ++it) {
353 QFile f(it.value());
354 if (f.open(QIODevice::ReadOnly))
355 buf = f.readAll();
356#ifndef QT_NO_COMPRESS
357 buf = qCompress(buf);
358#endif
359 svgBuffers.insert(it.key(), buf);
360 }
361 out << d->svgFiles << isCompressed << svgBuffers;
362 if (d->addedPixmaps)
363 out << (int)1 << *d->addedPixmaps;
364 else
365 out << (int)0;
366 }
367 else {
369 if (d->svgBuffers)
371 if (buf.isEmpty()) {
373 if (!svgFile.isEmpty()) {
374 QFile f(svgFile);
375 if (f.open(QIODevice::ReadOnly))
376 buf = f.readAll();
377 }
378 }
379#ifndef QT_NO_COMPRESS
380 buf = qCompress(buf);
381#endif
382 out << buf;
383 // 4.3 has buggy handling of added pixmaps, so don't write any
384 out << (int)0;
385 }
386 return true;
387}
388
390{
391 if (id == QIconEngine::IsNullHook) {
392 *reinterpret_cast<bool*>(data) = d->svgFiles.isEmpty() && !d->addedPixmaps && (!d->svgBuffers || d->svgBuffers->isEmpty());
393 }
395}
396
398
399#endif // QT_NO_SVGRENDERER
\inmodule QtCore
Definition qatomic.h:112
\inmodule QtCore
Definition qbytearray.h:57
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\inmodule QtCore
Definition qfile.h:93
static QGuiApplicationPrivate * instance()
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
const_iterator cbegin() const noexcept
Definition qhash.h:1214
T value(const Key &key) const noexcept
Definition qhash.h:1054
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
const_iterator cend() const noexcept
Definition qhash.h:1218
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:951
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:928
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
The QIconEngine class provides an abstract base class for QIcon renderers.
Definition qiconengine.h:15
virtual void virtual_hook(int id, void *data)
Mode
This enum type describes the mode for which a pixmap is intended to be used.
Definition qicon.h:22
@ Disabled
Definition qicon.h:22
@ Selected
Definition qicon.h:22
@ Normal
Definition qicon.h:22
@ Active
Definition qicon.h:22
State
This enum describes the state for which a pixmap is intended to be used.
Definition qicon.h:23
@ Off
Definition qicon.h:23
@ On
Definition qicon.h:23
\inmodule QtGui
Definition qimage.h:37
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
\inmodule QtCore
QMimeType mimeTypeForFile(const QString &fileName, MatchMode mode=MatchDefault) const
Returns a MIME type for the file named fileName using mode.
QString name
the name of the MIME type
Definition qmimetype.h:29
qreal devicePixelRatio() const
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
QPaintDevice * device() const
Returns the paint device on which this painter is currently painting, or \nullptr if the painter is n...
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device.
static bool find(const QString &key, QPixmap *pixmap)
Looks for a cached pixmap associated with the given key in the cache.
static bool insert(const QString &key, const QPixmap &pixmap)
Inserts a copy of the pixmap pixmap associated with the key into the cache.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QSize size() const
Returns the size of the pixmap.
Definition qpixmap.cpp:493
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition qpixmap.cpp:456
static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
Converts the given image to a pixmap using the specified flags to control the conversion.
Definition qpixmap.cpp:1437
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore
Definition qshareddata.h:19
\inmodule QtCore
Definition qsize.h:25
void scale(int w, int h, Qt::AspectRatioMode mode) noexcept
Scales the size to a rectangle with the given width and height, according to the specified mode:
Definition qsize.h:145
constexpr bool isNull() const noexcept
Returns true if both the width and height is 0; otherwise returns false.
Definition qsize.h:121
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:124
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
QHash< int, QPixmap > * addedPixmaps
bool tryLoad(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state)
QHash< int, QString > svgFiles
static int hashKey(QIcon::Mode mode, QIcon::State state)
QHash< int, QByteArray > * svgBuffers
static QAtomicInt lastSerialNum
QString pmcKey(const QSize &size, QIcon::Mode mode, QIcon::State state)
QIcon::Mode loadDataForModeAndState(QSvgRenderer *renderer, QIcon::Mode mode, QIcon::State state)
QIconEngine * clone() const override
Reimplement this method to return a clone of this icon engine.
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override
Returns the icon as a pixmap with the required size, mode, and state.
void virtual_hook(int id, void *data) override
bool read(QDataStream &in) override
Reads icon engine contents from the QDataStream in.
bool write(QDataStream &out) const override
Writes the contents of this engine to the QDataStream out.
void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) override
Called by QIcon::addFile().
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override
Returns the actual size of the icon the engine provides for the requested size, mode and state.
void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) override
Called by QIcon::addPixmap().
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override
Uses the given painter to paint the icon with the required mode and state into the rectangle rect.
QString key() const override
\variable QIconEngine::ScaledPixmapArgument::size
\inmodule QtSvg
void render(QPainter *p)
Renders the current document, or the current frame of an animated document, using the given painter.
QSize defaultSize() const
Returns the default size of the document contents.
bool isValid() const
Returns true if there is a valid current document; otherwise returns false.
bool load(const QString &filename)
Loads the SVG file specified by filename, returning true if the content was successfully parsed; othe...
QSet< QString >::iterator it
rect
[4]
else opt state
[0]
Combined button and popup list for selecting options.
@ KeepAspectRatio
@ CaseInsensitive
QByteArray qCompress(const uchar *data, qsizetype nbytes, int compressionLevel)
Q_CORE_EXPORT QByteArray qUncompress(const uchar *data, qsizetype nbytes)
#define qWarning
Definition qlogging.h:166
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint void * img
Definition qopenglext.h:233
GLuint in
GLfloat GLfloat p
[1]
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
@ OtherFile
@ CompressedSvgFile
@ SvgFile
static QByteArray maybeUncompress(const QByteArray &ba)
static FileType fileType(const QFileInfo &fi)
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
QByteArray ba
[0]
QTextStream out(stdout)
[7]
QSharedPointer< T > other(t)
[5]
QStringList fileNames
[4]
widget render & pixmap
QPainter painter(this)
[7]
QSvgRenderer * renderer
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18