Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsvgrenderer.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// Qt-Security score:significant reason:default
4
5
6#include "qsvgrenderer.h"
7
8#ifndef QT_NO_SVGRENDERER
9
10#include "qsvgdocument_p.h"
11
12#include "qbytearray.h"
13#include "qtimer.h"
14#include "qtransform.h"
15#include "qdebug.h"
16#include "private/qobject_p.h"
17
18
20
21/*!
22 \class QSvgRenderer
23 \inmodule QtSvg
24 \ingroup painting
25
26 \brief The QSvgRenderer class is used to draw the contents of SVG files onto paint devices.
27 \since 4.1
28 \reentrant
29
30 Using QSvgRenderer, Scalable Vector Graphics (SVG) can be rendered onto any QPaintDevice
31 subclass, including QWidget, QImage, and QGLWidget.
32
33 QSvgRenderer provides an API that supports basic features of SVG rendering, such as loading
34 and rendering of static drawings, and more interactive features like animation. Since the
35 rendering is performed using QPainter, SVG drawings can be rendered on any subclass of
36 QPaintDevice.
37
38 SVG drawings are either loaded when an QSvgRenderer is constructed, or loaded later
39 using the load() functions. Data is either supplied directly as serialized XML, or
40 indirectly using a file name. If a valid file has been loaded, either when the renderer
41 is constructed or at some later time, isValid() returns true; otherwise it returns false.
42 QSvgRenderer provides the render() slot to render the current document, or the current
43 frame of an animated document, using a given painter.
44
45 The defaultSize() function provides information about the amount of space that is required
46 to render the currently loaded SVG file. This is useful for paint devices, such as QWidget,
47 that often need to supply a size hint to their parent layout.
48 The default size of a drawing may differ from its visible area, found using the \l viewBox
49 property.
50
51 Animated SVG drawings are supported, and can be controlled with a simple collection of
52 functions and properties:
53
54 \list
55 \li The animated() function indicates whether a drawing contains animation information.
56 \omit
57 \li The animationDuration() function provides the duration in milliseconds of the
58 animation, without taking any looping into account.
59 \li The \l currentFrame property contains the current frame of the animation.
60 \endomit
61 \li The \l framesPerSecond property contains the rate at which the animation plays.
62 \endlist
63
64 Finally, the QSvgRenderer class provides the repaintNeeded() signal which is emitted
65 whenever the rendering of the document needs to be updated.
66
67 \sa QSvgWidget, {Qt SVG C++ Classes}, QPicture
68*/
69
71{
72 Q_DECLARE_PUBLIC(QSvgRenderer)
73public:
76 timer(0),
77 fps(30)
78 {
80 }
81
83 {
84 if (animationEnabled && render && render->animated() && fps > 0) {
86 timer->start(1000 / fps);
87 } else if (timer) {
88 timer->stop();
89 }
90 }
91
93 {
95 if (!timer) {
96 timer = new QTimer(q);
98 }
99 }
100
101 static void callRepaintNeeded(QSvgRenderer *const q);
102
104 {
105 static bool envOk = false;
106 static QtSvg::Options envOpts = QtSvg::Options::fromInt(
107 qEnvironmentVariableIntValue("QT_SVG_DEFAULT_OPTIONS", &envOk));
108 return envOk ? envOpts : appDefaultOptions;
109 }
110
113 int fps;
116 bool animationEnabled = true;
117};
118
120
121/*!
122 Constructs a new renderer with the given \a parent.
123*/
124QSvgRenderer::QSvgRenderer(QObject *parent)
125 : QObject(*(new QSvgRendererPrivate), parent)
126{
127}
128
129/*!
130 Constructs a new renderer with the given \a parent and loads the contents of the
131 SVG file with the specified \a filename.
132*/
133QSvgRenderer::QSvgRenderer(const QString &filename, QObject *parent)
134 : QObject(*new QSvgRendererPrivate, parent)
135{
136 load(filename);
137}
138
139/*!
140 Constructs a new renderer with the given \a parent and loads the SVG data
141 from the byte array specified by \a contents.
142*/
143QSvgRenderer::QSvgRenderer(const QByteArray &contents, QObject *parent)
144 : QObject(*new QSvgRendererPrivate, parent)
145{
146 load(contents);
147}
148
149/*!
150 \since 4.5
151
152 Constructs a new renderer with the given \a parent and loads the SVG data
153 using the stream reader specified by \a contents.
154*/
155QSvgRenderer::QSvgRenderer(QXmlStreamReader *contents, QObject *parent)
156 : QObject(*new QSvgRendererPrivate, parent)
157{
158 load(contents);
159}
160
161/*!
162 Destroys the renderer.
163*/
164QSvgRenderer::~QSvgRenderer()
165{
166
167}
168
169/*!
170 Returns true if there is a valid current document; otherwise returns false.
171*/
172bool QSvgRenderer::isValid() const
173{
174 Q_D(const QSvgRenderer);
175 return bool(d->render);
176}
177
178/*!
179 Returns the default size of the document contents.
180*/
181QSize QSvgRenderer::defaultSize() const
182{
183 Q_D(const QSvgRenderer);
184 if (d->render)
185 return d->render->size();
186 else
187 return QSize();
188}
189
190/*!
191 Returns viewBoxF().toRect().
192
193 \sa viewBoxF()
194*/
195QRect QSvgRenderer::viewBox() const
196{
197 Q_D(const QSvgRenderer);
198 if (d->render)
199 return d->render->viewBox().toRect();
200 else
201 return QRect();
202}
203
204/*!
205 \property QSvgRenderer::viewBox
206 \brief the rectangle specifying the visible area of the document in logical coordinates
207 \since 4.2
208*/
209void QSvgRenderer::setViewBox(const QRect &viewbox)
210{
211 Q_D(QSvgRenderer);
212 if (d->render)
213 d->render->setViewBox(viewbox);
214}
215
216/*!
217 Returns true if the current document contains animated elements; otherwise
218 returns false.
219
220 \sa framesPerSecond()
221*/
222bool QSvgRenderer::animated() const
223{
224 Q_D(const QSvgRenderer);
225 if (d->render)
226 return d->render->animated();
227 else
228 return false;
229}
230
231/*!
232 \property QSvgRenderer::animationEnabled
233 \brief whether the animation should run, if the SVG is animated
234
235 Setting the property to false stops the animation timer.
236 Setting the property to true starts the animation timer,
237 provided that the SVG contains animated elements.
238
239 If the SVG is not animated, the property will have no effect.
240 Otherwise, the property defaults to true.
241
242 \sa animated()
243
244 \since 6.7
245*/
246bool QSvgRenderer::isAnimationEnabled() const
247{
248 Q_D(const QSvgRenderer);
249 return d->animationEnabled;
250}
251
252void QSvgRenderer::setAnimationEnabled(bool enable)
253{
254 Q_D(QSvgRenderer);
255 d->animationEnabled = enable;
256 d->startOrStopTimer();
257}
258
259/*!
260 \property QSvgRenderer::framesPerSecond
261 \brief the number of frames per second to be shown
262
263 The number of frames per second is 0 if the current document is not animated.
264
265 \sa animated()
266*/
267int QSvgRenderer::framesPerSecond() const
268{
269 Q_D(const QSvgRenderer);
270 return d->fps;
271}
272
273void QSvgRenderer::setFramesPerSecond(int num)
274{
275 Q_D(QSvgRenderer);
276 if (num < 0) {
277 qWarning("QSvgRenderer::setFramesPerSecond: Cannot set negative value %d", num);
278 return;
279 }
280 d->fps = num;
281 d->startOrStopTimer();
282}
283
284/*!
285 \property QSvgRenderer::aspectRatioMode
286
287 \brief how rendering adheres to the SVG view box aspect ratio
288
289 The accepted modes are:
290 \list
291 \li Qt::IgnoreAspectRatio (the default): the aspect ratio is ignored and the
292 rendering is stretched to the target bounds.
293 \li Qt::KeepAspectRatio: rendering is centered and scaled as large as possible
294 within the target bounds while preserving aspect ratio.
295 \endlist
296
297 \since 5.15
298*/
299
300Qt::AspectRatioMode QSvgRenderer::aspectRatioMode() const
301{
302 Q_D(const QSvgRenderer);
303 if (d->render && d->render->preserveAspectRatio())
304 return Qt::KeepAspectRatio;
305 return Qt::IgnoreAspectRatio;
306}
307
308void QSvgRenderer::setAspectRatioMode(Qt::AspectRatioMode mode)
309{
310 Q_D(QSvgRenderer);
311 if (d->render) {
312 if (mode == Qt::KeepAspectRatio)
313 d->render->setPreserveAspectRatio(true);
314 else if (mode == Qt::IgnoreAspectRatio)
315 d->render->setPreserveAspectRatio(false);
316 }
317}
318
319/*!
320 \property QSvgRenderer::options
321 \since 6.7
322
323 This property holds a set of QtSvg::Option flags that can be used
324 to enable or disable various features of the parsing and rendering of SVG files.
325
326 In order to take effect, this property must be set \c before load() is executed. Note that the
327 constructors taking an SVG source parameter will perform loading during construction.
328
329 \sa setDefaultOptions
330 */
331QtSvg::Options QSvgRenderer::options() const
332{
333 Q_D(const QSvgRenderer);
334 return d->options;
335}
336
337void QSvgRenderer::setOptions(QtSvg::Options flags)
338{
339 Q_D(QSvgRenderer);
340 d->options = flags;
341}
342
343/*!
344 Sets the option flags that renderers will be created with to \a flags.
345 By default, no flags are set.
346
347 At runtime, this can be overridden by the QT_SVG_DEFAULT_OPTIONS environment variable.
348
349 \since 6.8
350*/
351
352void QSvgRenderer::setDefaultOptions(QtSvg::Options flags)
353{
354 QSvgRendererPrivate::appDefaultOptions = flags;
355}
356
357/*!
358 \property QSvgRenderer::currentFrame
359 \brief the current frame of the document's animation, or 0 if the document is not animated
360 \internal
361
362 \sa animationDuration(), framesPerSecond, animated()
363*/
364
365/*!
366 \internal
367*/
368int QSvgRenderer::currentFrame() const
369{
370 Q_D(const QSvgRenderer);
371 return d->render->currentFrame();
372}
373
374/*!
375 \internal
376*/
377void QSvgRenderer::setCurrentFrame(int frame)
378{
379 Q_D(QSvgRenderer);
380 d->render->setCurrentFrame(frame);
381}
382
383/*!
384 \internal
385
386 Returns the number of frames in the animation, or 0 if the current document is not
387 animated.
388
389 \sa animated(), framesPerSecond
390*/
391int QSvgRenderer::animationDuration() const
392{
393 Q_D(const QSvgRenderer);
394 return d->render->animationDuration();
395}
396
397/*!
398 \internal
399 \since 4.5
400
401 We can't have template functions, that's loadDocument(), as friends, for this
402 code, so we let this function be a friend of QSvgRenderer instead.
403 */
404void QSvgRendererPrivate::callRepaintNeeded(QSvgRenderer *const q)
405{
406 emit q->repaintNeeded();
407}
408
409template<typename TInputType>
410static bool loadDocument(QSvgRenderer *const q,
411 QSvgRendererPrivate *const d,
412 const TInputType &in)
413{
414 d->render = QSvgDocument::load(in, d->options);
415 if (d->render && !d->render->size().isValid())
416 d->render.reset();
417
418 d->startOrStopTimer();
419
420 if (d->render)
421 d->render->restartAnimation();
422
423 //force first update
424 QSvgRendererPrivate::callRepaintNeeded(q);
425
426 return bool(d->render);
427}
428
429/*!
430 Loads the SVG file specified by \a filename, returning true if the content
431 was successfully parsed; otherwise returns false.
432*/
433bool QSvgRenderer::load(const QString &filename)
434{
435 Q_D(QSvgRenderer);
436 return loadDocument(this, d, filename);
437}
438
439/*!
440 Loads the specified SVG format \a contents, returning true if the content
441 was successfully parsed; otherwise returns false.
442*/
443bool QSvgRenderer::load(const QByteArray &contents)
444{
445 Q_D(QSvgRenderer);
446 return loadDocument(this, d, contents);
447}
448
449/*!
450 Loads the specified SVG in \a contents, returning true if the content
451 was successfully parsed; otherwise returns false.
452
453 The reader will be used from where it currently is positioned. If \a contents
454 is \c null, behavior is undefined.
455
456 \since 4.5
457*/
458bool QSvgRenderer::load(QXmlStreamReader *contents)
459{
460 Q_D(QSvgRenderer);
461 return loadDocument(this, d, contents);
462}
463
464/*!
465 Renders the current document, or the current frame of an animated
466 document, using the given \a painter.
467*/
468void QSvgRenderer::render(QPainter *painter)
469{
470 Q_D(QSvgRenderer);
471 if (d->render) {
472 d->render->animator()->advanceAnimations();
473 d->render->draw(painter);
474 }
475}
476
477/*!
478 \fn void QSvgRenderer::repaintNeeded()
479
480 This signal is emitted whenever the rendering of the document
481 needs to be updated, usually for the purposes of animation.
482*/
483
484/*!
485 Renders the given element with \a elementId using the given \a painter
486 on the specified \a bounds. If the bounding rectangle is not specified
487 the SVG element is mapped to the whole paint device.
488*/
489void QSvgRenderer::render(QPainter *painter, const QString &elementId,
490 const QRectF &bounds)
491{
492 Q_D(QSvgRenderer);
493 if (d->render) {
494 d->render->animator()->advanceAnimations();
495 d->render->draw(painter, elementId, bounds);
496 }
497}
498
499/*!
500 Renders the current document, or the current frame of an animated document,
501 using the given \a painter on the specified \a bounds within the painter.
502 If \a bounds is not empty, the output will be scaled to fill it, ignoring
503 any aspect ratio implied by the SVG.
504*/
505void QSvgRenderer::render(QPainter *painter, const QRectF &bounds)
506{
507 Q_D(QSvgRenderer);
508 if (d->render) {
509 d->render->animator()->advanceAnimations();
510 d->render->draw(painter, bounds);
511 }
512}
513
514QRectF QSvgRenderer::viewBoxF() const
515{
516 Q_D(const QSvgRenderer);
517 if (d->render)
518 return d->render->viewBox();
519 else
520 return QRect();
521}
522
523void QSvgRenderer::setViewBox(const QRectF &viewbox)
524{
525 Q_D(QSvgRenderer);
526 if (d->render)
527 d->render->setViewBox(viewbox);
528}
529
530/*!
531 \since 4.2
532
533 Returns bounding rectangle of the item with the given \a id.
534 The transformation matrix of parent elements is not affecting
535 the bounds of the element.
536
537 \sa transformForElement()
538*/
539QRectF QSvgRenderer::boundsOnElement(const QString &id) const
540{
541 Q_D(const QSvgRenderer);
542 QRectF bounds;
543 if (d->render)
544 bounds = d->render->boundsOnElement(id);
545 return bounds;
546}
547
548
549/*!
550 \since 4.2
551
552 Returns true if the element with the given \a id exists
553 in the currently parsed SVG file and is a renderable
554 element.
555
556 Note: this method returns true only for elements that
557 can be rendered. Which implies that elements that are considered
558 part of the fill/stroke style properties, e.g. radialGradients
559 even tough marked with "id" attributes will not be found by this
560 method.
561*/
562bool QSvgRenderer::elementExists(const QString &id) const
563{
564 Q_D(const QSvgRenderer);
565 bool exists = false;
566 if (d->render)
567 exists = d->render->elementExists(id);
568 return exists;
569}
570
571/*!
572 \since 5.15
573
574 Returns the transformation matrix for the element
575 with the given \a id. The matrix is a product of
576 the transformation of the element's parents. The transformation of
577 the element itself is not included.
578
579 To find the bounding rectangle of the element in logical coordinates,
580 you can apply the matrix on the rectangle returned from boundsOnElement().
581
582 \sa boundsOnElement()
583*/
584QTransform QSvgRenderer::transformForElement(const QString &id) const
585{
586 Q_D(const QSvgRenderer);
587 QTransform trans;
588 if (d->render)
589 trans = d->render->transformForElement(id);
590 return trans;
591}
592
593QT_END_NAMESPACE
594
595#include "moc_qsvgrenderer.cpp"
596
597#endif // QT_NO_SVGRENDERER
static QtSvg::Options defaultOptions()
static QtSvg::Options appDefaultOptions
std::unique_ptr< QSvgDocument > render
QtSvg::Options options
Combined button and popup list for selecting options.
static bool loadDocument(QSvgRenderer *const q, QSvgRendererPrivate *const d, const TInputType &in)