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
qquickvectorimage.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 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
4#include <QtCore/qurl.h>
7#include <QtQuickVectorImageGenerator/private/qquickitemgenerator_p.h>
8#include <QtQuickVectorImageGenerator/private/qquickvectorimageglobal_p.h>
9#include <QtQuickVectorImageGenerator/private/qquickvectorimageplugin_p.h>
10#include <QtCore/qloggingcategory.h>
11
12#include <private/qquicktranslate_p.h>
13#include <private/qquickanimation_p.h>
14
15#include <private/qfactoryloader_p.h>
16
18
19Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, vectorImagePluginLoader,
20 (QQuickVectorImageFormatsPluginFactory_iid,
21 QLatin1String("/vectorimageformats"),
22 Qt::CaseInsensitive))
23
24
25/*!
26 \qmlmodule QtQuick.VectorImage
27 \title Qt Quick Vector Image QML Types
28 \ingroup qmlmodules
29 \brief Provides QML types for displaying vector image files.
30 \since 6.8
31
32 To use the types in this module, import the module with the following line:
33
34 \qml
35 import QtQuick.VectorImage
36 \endqml
37
38 Qt Quick Vector Image provides support for displaying vector image files in a Qt Quick
39 scene.
40
41 It currently supports the \c SVG file format. In addition, Lottie support
42 can be enabled by setting the
43 \l{QtQuick.VectorImage::VectorImage::}{assumeTrustedSource} property to true
44 and including the plugin from the \l{Qt Lottie Animation} module.
45
46 Qt supports multiple options for displaying SVG files. For an overview and comparison of
47 the different ones, see the documentation of the \l{svgtoqml} tool.
48
49 \section1 QML Types
50*/
51
52void QQuickVectorImagePrivate::setSource(const QUrl &source)
53{
54 Q_Q(QQuickVectorImage);
55 if (sourceFile == source)
56 return;
57
58 sourceFile = source;
59 loadFile();
60 emit q->sourceChanged();
61}
62
64{
65 Q_Q(QQuickVectorImage);
66
67 if (!q->isComponentComplete())
68 return;
69
70 QUrl resolvedUrl = qmlContext(q)->resolvedUrl(sourceFile);
71 QString localFile = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
72
73 if (localFile.isEmpty())
74 return;
75
76 if (rootItem)
77 rootItem->deleteLater();
78
79 rootItem = new QQuickItem(q);
80 rootItem->setParentItem(q);
81
82 QQuickVectorImageGenerator::GeneratorFlags flags;
83 if (preferredRendererType == QQuickVectorImage::CurveRenderer)
84 flags.setFlag(QQuickVectorImageGenerator::CurveRenderer);
86 flags.setFlag(QQuickVectorImageGenerator::AssumeTrustedSource);
87 if (m_asyncShapes)
88 flags.setFlag(QQuickVectorImageGenerator::AsyncShapes);
89
90 if (!m_qmlContext || m_qmlContext->engine() != qmlContext(q)->engine())
91 m_qmlContext.reset(new QQmlContext(qmlContext(q)->engine()));
92
93 QQuickItemGenerator generator(localFile, flags, rootItem, m_qmlContext.get());
94
95 // If we assume trusted source, we try plugins first
96 bool generatedWithPlugin = false;
98 QFactoryLoader *loader = vectorImagePluginLoader();
99
100 const qsizetype count = loader->keyMap().size();
101 for (qsizetype i = 0; i <= count && !generatedWithPlugin; ++i) {
102 QQuickVectorImagePlugin *plugin = qobject_cast<QQuickVectorImagePlugin *>(loader->instance(i));
103 if (plugin != nullptr)
104 generatedWithPlugin = plugin->generate(localFile, &generator);
105 }
106 }
107
108 if (!generatedWithPlugin)
109 generator.generate();
110
111 q->setImplicitWidth(rootItem->width());
112 q->setImplicitHeight(rootItem->height());
113
114 static int freezeTime = qEnvironmentVariableIntValue("QT_QUICKVECTORIMAGE_FREEZE");
115 if (freezeTime != 0) {
116 if (freezeTime < 0)
117 freezeTime = 400; // TBD: calculate better default, e.g. midtime of total anim duration
118 q->animations()->setPaused(true);
119 const QList<QQuickAbstractAnimation *> anims = rootItem->findChildren<QQuickAbstractAnimation *>();
120 for (QQuickAbstractAnimation *anim : anims) {
121 if (anim->group() == nullptr)
122 anim->setCurrentTime(freezeTime);
123 }
124 }
125
126 q->updateAnimationProperties();
127 q->updateRootItemScale();
128 q->update();
129}
130
131/*!
132 \qmltype VectorImage
133 \inqmlmodule QtQuick.VectorImage
134 \inherits Item
135 \brief Loads a vector image file and displays it in a Qt Quick scene.
136 \since 6.8
137
138 The VectorImage can be used to load a vector image file and display this as an item in a Qt
139 Quick scene.
140
141 It currently supports the \c SVG file format. In addition, Lottie support can be enabled by
142 setting the \l{assumeTrustedSource} property to true and including the plugin from the
143 \l{Qt Lottie Animation} module.
144
145 \note This complements the approach of loading the vector image file through an \l Image
146 element: \l Image creates a raster version of the image at the requested size. VectorImage
147 builds a Qt Quick scene that represents the image. This means the resulting item can be scaled
148 and rotated without losing quality, and it will typically consume less memory than the
149 rasterized version.
150*/
151QQuickVectorImage::QQuickVectorImage(QQuickItem *parent)
152 : QQuickItem(*(new QQuickVectorImagePrivate), parent)
153{
154 setFlag(QQuickItem::ItemHasContents, true);
155
156 QObject::connect(this, &QQuickItem::widthChanged, this, &QQuickVectorImage::updateRootItemScale);
157 QObject::connect(this, &QQuickItem::heightChanged, this, &QQuickVectorImage::updateRootItemScale);
158 QObject::connect(this, &QQuickVectorImage::fillModeChanged, this, &QQuickVectorImage::updateRootItemScale);
159}
160
161/*!
162 \qmlproperty url QtQuick.VectorImage::VectorImage::source
163
164 This property holds the URL of the vector image file to load.
165
166 VectorImage currently supports the \c SVG file format. In addition, Lottie support can be
167 enabled by setting the \l{assumeTrustedSource} property to true and including the plugin from
168 the \l{Qt Lottie Animation} module.
169*/
170QUrl QQuickVectorImage::source() const
171{
172 Q_D(const QQuickVectorImage);
173 return d->sourceFile;
174}
175
176void QQuickVectorImage::setSource(const QUrl &source)
177{
178 Q_D(QQuickVectorImage);
179 d->setSource(source);
180}
181
182void QQuickVectorImage::updateRootItemScale()
183{
184 Q_D(QQuickVectorImage);
185
186 if (d->rootItem == nullptr
187 || qFuzzyIsNull(d->rootItem->width())
188 || qFuzzyIsNull(d->rootItem->height())) {
189 return;
190 }
191
192 auto xformProp = d->rootItem->transform();
193 QQuickScale *scaleTransform = nullptr;
194 if (xformProp.count(&xformProp) == 0) {
195 scaleTransform = new QQuickScale;
196 scaleTransform->setParent(d->rootItem);
197 xformProp.append(&xformProp, scaleTransform);
198 } else {
199 scaleTransform = qobject_cast<QQuickScale *>(xformProp.at(&xformProp, 0));
200 }
201
202 if (scaleTransform != nullptr) {
203 qreal xScale = width() / d->rootItem->width();
204 qreal yScale = height() / d->rootItem->height();
205
206 switch (d->fillMode) {
207 case QQuickVectorImage::NoResize:
208 xScale = yScale = 1.0;
209 break;
210 case QQuickVectorImage::PreserveAspectFit:
211 xScale = yScale = qMin(xScale, yScale);
212 break;
213 case QQuickVectorImage::PreserveAspectCrop:
214 xScale = yScale = qMax(xScale, yScale);
215 break;
216 case QQuickVectorImage::Stretch:
217 // Already correct
218 break;
219 };
220
221 scaleTransform->setXScale(xScale);
222 scaleTransform->setYScale(yScale);
223 }
224}
225
226void QQuickVectorImage::updateAnimationProperties()
227{
228 Q_D(QQuickVectorImage);
229 if (Q_UNLIKELY(d->rootItem == nullptr || d->rootItem->childItems().isEmpty()))
230 return;
231
232 QQuickItem *childItem = d->rootItem->childItems().first();
233 if (Q_LIKELY(d->animations != nullptr)) {
234 childItem->setProperty("loops", d->animations->loops());
235 childItem->setProperty("paused", d->animations->paused());
236 }
237}
238
239QQuickVectorImageAnimations *QQuickVectorImage::animations()
240{
241 Q_D(QQuickVectorImage);
242 if (d->animations == nullptr) {
243 d->animations = new QQuickVectorImageAnimations;
244 QQml_setParent_noEvent(d->animations, this);
245 QObject::connect(d->animations, &QQuickVectorImageAnimations::loopsChanged, this, &QQuickVectorImage::updateAnimationProperties);
246 QObject::connect(d->animations, &QQuickVectorImageAnimations::pausedChanged, this, &QQuickVectorImage::updateAnimationProperties);
247 }
248
249 return d->animations;
250}
251
252/*!
253 \qmlproperty enumeration QtQuick.VectorImage::VectorImage::fillMode
254
255 This property defines what happens if the width and height of the VectorImage differs from
256 the implicit size of its contents.
257
258 \value VectorImage.NoResize The contents are still rendered at the size provided by
259 the input.
260 \value VectorImage.Stretch The contents are scaled to match the width and height of
261 the \c{VectorImage}. (This is the default.)
262 \value VectorImage.PreserveAspectFit The contents are scaled to fit inside the bounds of the
263 \c VectorImage, while preserving aspect ratio. The
264 actual bounding rect of the contents will sometimes be
265 smaller than the \c VectorImage item.
266 \value VectorImage.PreserveAspectCrop The contents are scaled to fill the \c VectorImage item,
267 while preserving the aspect ratio. The actual bounds of
268 the contents will sometimes be larger than the
269 \c VectorImage item.
270*/
271
272QQuickVectorImage::FillMode QQuickVectorImage::fillMode() const
273{
274 Q_D(const QQuickVectorImage);
275 return d->fillMode;
276}
277
278void QQuickVectorImage::setFillMode(FillMode newFillMode)
279{
280 Q_D(QQuickVectorImage);
281 if (d->fillMode == newFillMode)
282 return;
283 d->fillMode = newFillMode;
284 emit fillModeChanged();
285}
286
287/*!
288 \qmlproperty enumeration QtQuick.VectorImage::VectorImage::preferredRendererType
289
290 Requests a specific backend to use for rendering shapes in the \c VectorImage.
291
292 \value VectorImage.GeometryRenderer Equivalent to Shape.GeometryRenderer. This backend flattens
293 curves and triangulates the result. It will give aliased results unless multi-sampling is
294 enabled, and curve flattening may be visible when the item is scaled.
295 \value VectorImage.CurveRenderer Equivalent to Shape.CurveRenderer. With this backend, curves
296 are rendered on the GPU and anti-aliasing is built in. Will typically give better visual
297 results, but at some extra cost to performance.
298
299 The default is \c{VectorImage.GeometryRenderer}.
300*/
301
302QQuickVectorImage::RendererType QQuickVectorImage::preferredRendererType() const
303{
304 Q_D(const QQuickVectorImage);
305 return d->preferredRendererType;
306}
307
308void QQuickVectorImage::setPreferredRendererType(RendererType newPreferredRendererType)
309{
310 Q_D(QQuickVectorImage);
311 if (d->preferredRendererType == newPreferredRendererType)
312 return;
313 d->preferredRendererType = newPreferredRendererType;
314 d->loadFile();
315 emit preferredRendererTypeChanged();
316}
317
318/*!
319 \qmlproperty bool QtQuick.VectorImage::VectorImage::asynchronousShapes
320 \since 6.11
321
322 This property controls the {QtQuick.Shapes::Shape::asynchronous}{asynchronous} property of the
323 \l Shape items in the Quick scene that VectorImage builds to represent the image.
324
325 Setting this property to \c true will offload the CPU part of the rendering processing of the
326 shapes to separate worker threads. This can improve CPU utilization and user interface
327 responsiveness.
328
329 By default this property is \c false.
330*/
331
332bool QQuickVectorImage::asynchronousShapes() const
333{
334 Q_D(const QQuickVectorImage);
335 return d->m_asyncShapes;
336}
337
338void QQuickVectorImage::setAsynchronousShapes(bool asynchronous)
339{
340 Q_D(QQuickVectorImage);
341 if (d->m_asyncShapes == asynchronous)
342 return;
343 d->m_asyncShapes = asynchronous;
344 emit asynchronousShapesChanged();
345}
346
347/*!
348 \qmlproperty bool QtQuick.VectorImage::VectorImage::assumeTrustedSource
349 \since 6.10
350
351 Setting this to true when loading trusted source files expands support for some features that
352 may be unsafe in an uncontrolled setting. For SVG in particular, this maps to the
353 \l{QtSvg::Option}{AssumeTrustedSource option}.
354
355 When this is set to true, VectorImage will also try to load the image using the Lottie format
356 plugin if this is available. See \l{Qt Lottie Animation} for additional information.
357
358 By default this property is \c false.
359
360 \sa svgtoqml, lottietoqml
361 */
362
363bool QQuickVectorImage::assumeTrustedSource() const
364{
365 Q_D(const QQuickVectorImage);
366 return d->assumeTrustedSource;
367}
368
369void QQuickVectorImage::setAssumeTrustedSource(bool assumeTrustedSource)
370{
371 Q_D(QQuickVectorImage);
372 if (d->assumeTrustedSource == assumeTrustedSource)
373 return;
374 d->assumeTrustedSource = assumeTrustedSource;
375 d->loadFile();
376 emit assumeTrustedSourceChanged();
377}
378
379void QQuickVectorImage::componentComplete()
380{
381 Q_D(QQuickVectorImage);
382 QQuickItem::componentComplete();
383
384 d->loadFile();
385}
386
387/*!
388 \qmlpropertygroup QtQuick.VectorImage::VectorImage::animations
389 \qmlproperty bool QtQuick.VectorImage::VectorImage::animations.paused
390 \qmlproperty int QtQuick.VectorImage::VectorImage::animations.loops
391 \since 6.10
392
393 These properties can be used to control animations in the image, if it contains any.
394
395 The \c paused property can be set to true to temporarily pause all animations. When the
396 property is reset to \c false, the animations will resume where they were. By default this
397 property is \c false.
398
399 The \c loops property defines the number of times the animations in the document will repeat.
400 By default this property is 1. Any animations that is set to loop indefinitely in the source
401 image will be unaffected by this property. To make all animations in the document repeat
402 indefinitely, the \c loops property can be set to \c{Animation.Infinite}.
403*/
404int QQuickVectorImageAnimations::loops() const
405{
406 return m_loops;
407}
408
409void QQuickVectorImageAnimations::setLoops(int loops)
410{
411 if (m_loops == loops)
412 return;
413 m_loops = loops;
414 emit loopsChanged();
415}
416
417bool QQuickVectorImageAnimations::paused() const
418{
419 return m_paused;
420}
421
422void QQuickVectorImageAnimations::setPaused(bool paused)
423{
424 if (m_paused == paused)
425 return;
426 m_paused = paused;
427 emit pausedChanged();
428}
429
430void QQuickVectorImageAnimations::restart()
431{
432 QQuickVectorImage *parentVectorImage = qobject_cast<QQuickVectorImage *>(parent());
433 if (Q_UNLIKELY(parentVectorImage == nullptr)) {
434 qCWarning(lcQuickVectorImage) << Q_FUNC_INFO << "Parent is not a VectorImage";
435 return;
436 }
437
438 QQuickVectorImagePrivate *d = QQuickVectorImagePrivate::get(parentVectorImage);
439
440 if (Q_UNLIKELY(d->rootItem == nullptr || d->rootItem->childItems().isEmpty()))
441 return;
442
443 QQuickItem *childItem = d->rootItem->childItems().first();
444 QMetaObject::invokeMethod(childItem, "restart");
445}
446
447QT_END_NAMESPACE
448
449#include <moc_qquickvectorimage_p.cpp>
Combined button and popup list for selecting options.