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 {
78 }
79
81 {
82 if (animationEnabled && render && render->animated() && fps > 0) {
84 timer->start(1000 / fps);
85 } else if (timer) {
86 timer->stop();
87 }
88 }
89
91 {
93 if (!timer) {
94 timer = new QTimer(q);
96 }
97 }
98
99 static void callRepaintNeeded(QSvgRenderer *const q);
100
102 {
103 static bool envOk = false;
104 static QtSvg::Options envOpts = QtSvg::Options::fromInt(
105 qEnvironmentVariableIntValue("QT_SVG_DEFAULT_OPTIONS", &envOk));
106 return envOk ? envOpts : appDefaultOptions;
107 }
108
110 QTimer *timer{nullptr};
111 int fps{30};
115};
116
118
119/*!
120 Constructs a new renderer with the given \a parent.
121*/
122QSvgRenderer::QSvgRenderer(QObject *parent)
123 : QObject(*(new QSvgRendererPrivate), parent)
124{
125}
126
127/*!
128 Constructs a new renderer with the given \a parent and loads the contents of the
129 SVG file with the specified \a filename.
130*/
131QSvgRenderer::QSvgRenderer(const QString &filename, QObject *parent)
132 : QObject(*new QSvgRendererPrivate, parent)
133{
134 load(filename);
135}
136
137/*!
138 Constructs a new renderer with the given \a parent and loads the SVG data
139 from the byte array specified by \a contents.
140*/
141QSvgRenderer::QSvgRenderer(const QByteArray &contents, QObject *parent)
142 : QObject(*new QSvgRendererPrivate, parent)
143{
144 load(contents);
145}
146
147/*!
148 \since 4.5
149
150 Constructs a new renderer with the given \a parent and loads the SVG data
151 using the stream reader specified by \a contents.
152*/
153QSvgRenderer::QSvgRenderer(QXmlStreamReader *contents, QObject *parent)
154 : QObject(*new QSvgRendererPrivate, parent)
155{
156 load(contents);
157}
158
159/*!
160 Destroys the renderer.
161*/
162QSvgRenderer::~QSvgRenderer()
163{
164
165}
166
167/*!
168 Returns true if there is a valid current document; otherwise returns false.
169*/
170bool QSvgRenderer::isValid() const
171{
172 Q_D(const QSvgRenderer);
173 return bool(d->render);
174}
175
176/*!
177 Returns the default size of the document contents.
178*/
179QSize QSvgRenderer::defaultSize() const
180{
181 Q_D(const QSvgRenderer);
182 if (d->render)
183 return d->render->size();
184 else
185 return QSize();
186}
187
188/*!
189 Returns viewBoxF().toRect().
190
191 \sa viewBoxF()
192*/
193QRect QSvgRenderer::viewBox() const
194{
195 Q_D(const QSvgRenderer);
196 if (d->render)
197 return d->render->viewBox().toRect();
198 else
199 return QRect();
200}
201
202/*!
203 \property QSvgRenderer::viewBox
204 \brief the rectangle specifying the visible area of the document in logical coordinates
205 \since 4.2
206*/
207void QSvgRenderer::setViewBox(const QRect &viewbox)
208{
209 Q_D(QSvgRenderer);
210 if (d->render)
211 d->render->setViewBox(viewbox);
212}
213
214/*!
215 Returns true if the current document contains animated elements; otherwise
216 returns false.
217
218 \sa framesPerSecond()
219*/
220bool QSvgRenderer::animated() const
221{
222 Q_D(const QSvgRenderer);
223 if (d->render)
224 return d->render->animated();
225 else
226 return false;
227}
228
229/*!
230 \property QSvgRenderer::animationEnabled
231 \brief whether the animation should run, if the SVG is animated
232
233 Setting the property to false stops the animation timer.
234 Setting the property to true starts the animation timer,
235 provided that the SVG contains animated elements.
236
237 If the SVG is not animated, the property will have no effect.
238 Otherwise, the property defaults to true.
239
240 \sa animated()
241
242 \since 6.7
243*/
244bool QSvgRenderer::isAnimationEnabled() const
245{
246 Q_D(const QSvgRenderer);
247 return d->animationEnabled;
248}
249
250void QSvgRenderer::setAnimationEnabled(bool enable)
251{
252 Q_D(QSvgRenderer);
253 d->animationEnabled = enable;
254 d->startOrStopTimer();
255}
256
257/*!
258 \property QSvgRenderer::framesPerSecond
259 \brief the number of frames per second to be shown
260
261 The number of frames per second is 0 if the current document is not animated.
262
263 \sa animated()
264*/
265int QSvgRenderer::framesPerSecond() const
266{
267 Q_D(const QSvgRenderer);
268 return d->fps;
269}
270
271void QSvgRenderer::setFramesPerSecond(int num)
272{
273 Q_D(QSvgRenderer);
274 if (num < 0) {
275 qWarning("QSvgRenderer::setFramesPerSecond: Cannot set negative value %d", num);
276 return;
277 }
278 d->fps = num;
279 d->startOrStopTimer();
280}
281
282/*!
283 \property QSvgRenderer::aspectRatioMode
284
285 \brief how rendering adheres to the SVG view box aspect ratio
286
287 The accepted modes are:
288 \list
289 \li Qt::IgnoreAspectRatio (the default): the aspect ratio is ignored and the
290 rendering is stretched to the target bounds.
291 \li Qt::KeepAspectRatio: rendering is centered and scaled as large as possible
292 within the target bounds while preserving aspect ratio.
293 \endlist
294
295 \since 5.15
296*/
297
298Qt::AspectRatioMode QSvgRenderer::aspectRatioMode() const
299{
300 Q_D(const QSvgRenderer);
301 if (d->render && d->render->preserveAspectRatio())
302 return Qt::KeepAspectRatio;
303 return Qt::IgnoreAspectRatio;
304}
305
306void QSvgRenderer::setAspectRatioMode(Qt::AspectRatioMode mode)
307{
308 Q_D(QSvgRenderer);
309 if (d->render) {
310 if (mode == Qt::KeepAspectRatio)
311 d->render->setPreserveAspectRatio(true);
312 else if (mode == Qt::IgnoreAspectRatio)
313 d->render->setPreserveAspectRatio(false);
314 }
315}
316
317/*!
318 \property QSvgRenderer::options
319 \since 6.7
320
321 This property holds a set of QtSvg::Option flags that can be used
322 to enable or disable various features of the parsing and rendering of SVG files.
323
324 In order to take effect, this property must be set \c before load() is executed. Note that the
325 constructors taking an SVG source parameter will perform loading during construction.
326
327 \sa setDefaultOptions
328 */
329QtSvg::Options QSvgRenderer::options() const
330{
331 Q_D(const QSvgRenderer);
332 return d->options;
333}
334
335void QSvgRenderer::setOptions(QtSvg::Options flags)
336{
337 Q_D(QSvgRenderer);
338 d->options = flags;
339}
340
341/*!
342 Sets the option flags that renderers will be created with to \a flags.
343 By default, no flags are set.
344
345 At runtime, this can be overridden by the QT_SVG_DEFAULT_OPTIONS environment variable.
346
347 \since 6.8
348*/
349
350void QSvgRenderer::setDefaultOptions(QtSvg::Options flags)
351{
352 QSvgRendererPrivate::appDefaultOptions = flags;
353}
354
355/*!
356 \property QSvgRenderer::currentFrame
357 \brief the current frame of the document's animation, or 0 if the document is not animated
358 \internal
359
360 \sa animationDuration(), framesPerSecond, animated()
361*/
362
363/*!
364 \internal
365*/
366int QSvgRenderer::currentFrame() const
367{
368 Q_D(const QSvgRenderer);
369 return d->render->currentFrame();
370}
371
372/*!
373 \internal
374*/
375void QSvgRenderer::setCurrentFrame(int frame)
376{
377 Q_D(QSvgRenderer);
378 d->render->setCurrentFrame(frame);
379}
380
381/*!
382 \internal
383
384 Returns the number of frames in the animation, or 0 if the current document is not
385 animated.
386
387 \sa animated(), framesPerSecond
388*/
389int QSvgRenderer::animationDuration() const
390{
391 Q_D(const QSvgRenderer);
392 return d->render->animationDuration();
393}
394
395/*!
396 \internal
397 \since 4.5
398
399 We can't have template functions, that's loadDocument(), as friends, for this
400 code, so we let this function be a friend of QSvgRenderer instead.
401 */
402void QSvgRendererPrivate::callRepaintNeeded(QSvgRenderer *const q)
403{
404 emit q->repaintNeeded();
405}
406
407template<typename TInputType>
408static bool loadDocument(QSvgRenderer *const q,
409 QSvgRendererPrivate *const d,
410 const TInputType &in)
411{
412 d->render = QSvgDocument::load(in, d->options);
413 if (d->render && !d->render->size().isValid())
414 d->render.reset();
415
416 d->startOrStopTimer();
417
418 if (d->render)
419 d->render->restartAnimation();
420
421 //force first update
422 QSvgRendererPrivate::callRepaintNeeded(q);
423
424 return bool(d->render);
425}
426
427/*!
428 Loads the SVG file specified by \a filename, returning true if the content
429 was successfully parsed; otherwise returns false.
430*/
431bool QSvgRenderer::load(const QString &filename)
432{
433 Q_D(QSvgRenderer);
434 return loadDocument(this, d, filename);
435}
436
437/*!
438 Loads the specified SVG format \a contents, returning true if the content
439 was successfully parsed; otherwise returns false.
440*/
441bool QSvgRenderer::load(const QByteArray &contents)
442{
443 Q_D(QSvgRenderer);
444 return loadDocument(this, d, contents);
445}
446
447/*!
448 Loads the specified SVG in \a contents, returning true if the content
449 was successfully parsed; otherwise returns false.
450
451 The reader will be used from where it currently is positioned. If \a contents
452 is \c null, behavior is undefined.
453
454 \since 4.5
455*/
456bool QSvgRenderer::load(QXmlStreamReader *contents)
457{
458 Q_D(QSvgRenderer);
459 return loadDocument(this, d, contents);
460}
461
462/*!
463 Renders the current document, or the current frame of an animated
464 document, using the given \a painter.
465*/
466void QSvgRenderer::render(QPainter *painter)
467{
468 Q_D(QSvgRenderer);
469 if (d->render) {
470 if (d->render->animator())
471 d->render->animator()->advanceAnimations();
472 d->render->draw(painter);
473 }
474}
475
476/*!
477 \fn void QSvgRenderer::repaintNeeded()
478
479 This signal is emitted whenever the rendering of the document
480 needs to be updated, usually for the purposes of animation.
481*/
482
483/*!
484 Renders the given element with \a elementId using the given \a painter
485 on the specified \a bounds. If the bounding rectangle is not specified
486 the SVG element is mapped to the whole paint device.
487*/
488void QSvgRenderer::render(QPainter *painter, const QString &elementId,
489 const QRectF &bounds)
490{
491 Q_D(QSvgRenderer);
492 if (d->render) {
493 if (d->render->animator())
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 if (d->render->animator())
510 d->render->animator()->advanceAnimations();
511 d->render->draw(painter, bounds);
512 }
513}
514
515QRectF QSvgRenderer::viewBoxF() const
516{
517 Q_D(const QSvgRenderer);
518 if (d->render)
519 return d->render->viewBox();
520 else
521 return QRect();
522}
523
524void QSvgRenderer::setViewBox(const QRectF &viewbox)
525{
526 Q_D(QSvgRenderer);
527 if (d->render)
528 d->render->setViewBox(viewbox);
529}
530
531/*!
532 \since 4.2
533
534 Returns bounding rectangle of the item with the given \a id.
535 The transformation matrix of parent elements is not affecting
536 the bounds of the element.
537
538 \sa transformForElement()
539*/
540QRectF QSvgRenderer::boundsOnElement(const QString &id) const
541{
542 Q_D(const QSvgRenderer);
543 QRectF bounds;
544 if (d->render)
545 bounds = d->render->boundsOnElement(id);
546 return bounds;
547}
548
549
550/*!
551 \since 4.2
552
553 Returns true if the element with the given \a id exists
554 in the currently parsed SVG file and is a renderable
555 element.
556
557 Note: this method returns true only for elements that
558 can be rendered. Which implies that elements that are considered
559 part of the fill/stroke style properties, e.g. radialGradients
560 even tough marked with "id" attributes will not be found by this
561 method.
562*/
563bool QSvgRenderer::elementExists(const QString &id) const
564{
565 Q_D(const QSvgRenderer);
566 bool exists = false;
567 if (d->render)
568 exists = d->render->elementExists(id);
569 return exists;
570}
571
572/*!
573 \since 5.15
574
575 Returns the transformation matrix for the element
576 with the given \a id. The matrix is a product of
577 the transformation of the element's parents. The transformation of
578 the element itself is not included.
579
580 To find the bounding rectangle of the element in logical coordinates,
581 you can apply the matrix on the rectangle returned from boundsOnElement().
582
583 \sa boundsOnElement()
584*/
585QTransform QSvgRenderer::transformForElement(const QString &id) const
586{
587 Q_D(const QSvgRenderer);
588 QTransform trans;
589 if (d->render)
590 trans = d->render->transformForElement(id);
591 return trans;
592}
593
594QT_END_NAMESPACE
595
596#include "moc_qsvgrenderer.cpp"
597
598#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)