4#include <QtCore/qurl.h>
5#include <QtCore/QScopeGuard>
10#include <QtQuickVectorImageGenerator/private/qquickitemgenerator_p.h>
11#include <QtQuickVectorImageGenerator/private/qquickvectorimageglobal_p.h>
12#include <QtQuickVectorImageGenerator/private/qquickanimationrootitem_p.h>
13#include <QtCore/private/qfactoryloader_p.h>
14#include <QtCore/qloggingcategory.h>
16#include <private/qquicktranslate_p.h>
17#include <private/qquickanimation_p.h>
21Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, itemGenPluginLoader,
23 QLatin1String(
"/vectorimageformats"), Qt::CaseInsensitive))
25static bool useQmlGenerator()
27 static const bool val = !qEnvironmentVariableIsSet(
"QT_QUICKVECTORIMAGE_USE_ITEM_GENERATOR");
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
60 Q_Q(QQuickVectorImage);
61 if (sourceFile == source)
66 emit q->sourceChanged();
71 Q_Q(QQuickVectorImage);
73 if (!q->isComponentComplete())
76 QQmlContext *ctx = qmlContext(q);
77 QUrl resolvedUrl = ctx->resolvedUrl(sourceFile);
78 QString localFile = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
80 if (rootItem && (!retainWhileLoading || localFile.isEmpty())) {
81 rootItem->deleteLater();
83 emit q->generatedItemChanged();
85 emit q->statusChanged();
88 if (localFile.isEmpty())
101 if (pendingRootItem !=
nullptr) {
102 delete pendingRootItem;
103 pendingRootItem =
nullptr;
106 QQuickVectorImageGenerator::GeneratorFlags flags;
107 if (preferredRendererType == QQuickVectorImage::CurveRenderer)
108 flags.setFlag(QQuickVectorImageGenerator::CurveRenderer);
110 flags.setFlag(QQuickVectorImageGenerator::AssumeTrustedSource);
112 flags.setFlag(QQuickVectorImageGenerator::AsyncShapes);
114 flags.setFlag(QQuickVectorImageGenerator::AsynchronousLoading);
116 if (useQmlGenerator()) {
117 QQmlIncubator::IncubationMode mode =
118 asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::Synchronous;
120 if (!context || context->engine() != qmlContext(q)->engine())
121 context.reset(
new QQmlContext(qmlContext(q)->engine()));
123 incubator =
new QQuickVectorImageIncubator(mode, context.get(), q);
124 QObject::connect(incubator, &QQuickVectorImageIncubator::statusUpdated, q,
125 &QQuickVectorImage::updateItem);
128 QQuickItemGenerator gen(localFile, flags, qmlContext(q));
130 bool generatedWithPlugin =
false;
131 if (flags.testFlag(QQuickVectorImageGenerator::AssumeTrustedSource)) {
132 QFactoryLoader *loader = itemGenPluginLoader();
133 const qsizetype count = loader->keyMap().size();
134 for (qsizetype i = 0; i < count && !generatedWithPlugin; ++i) {
135 QQuickVectorImagePlugin *plugin =
136 qobject_cast<QQuickVectorImagePlugin *>(loader->instance(i));
137 if (plugin !=
nullptr) {
138 std::unique_ptr<QQuickVectorImagePluginGenerator> pluginGen(
139 plugin->createGenerator(localFile));
140 if (pluginGen !=
nullptr)
141 generatedWithPlugin = pluginGen->generate(localFile, &gen);
146 if (!generatedWithPlugin)
149 if (gen.errorState() == QQuickVectorImageGenerator::NoError) {
150 pendingRootItem = gen.takeRootItem();
152 qCWarning(lcQuickVectorImage) <<
"QQuickItemGenerator: failed to generate" << localFile
153 <<
"(errorState:" << gen.errorState() <<
")";
159void QQuickVectorImage::updateItem()
161 Q_D(QQuickVectorImage);
163 const QQuickItem *oldGenItem = generatedItem();
164 auto emitter = qScopeGuard([&] {
165 if (generatedItem() != oldGenItem)
166 emit generatedItemChanged();
167 emit statusChanged();
170 QQuickItem *item =
nullptr;
171 if (d->incubator !=
nullptr) {
172 if (d->incubator->object() ==
nullptr || !d->incubator->isReady())
174 item = qobject_cast<QQuickItem *>(d->incubator->object());
175 if (item ==
nullptr) {
176 qCWarning(lcQuickVectorImage)
177 <<
"QQuickVectorImage::updateItem: Root item not a QQuickItem:"
178 << d->incubator->errors();
182 item = d->pendingRootItem;
183 d->pendingRootItem =
nullptr;
188 if (d->rootItem !=
nullptr)
189 d->rootItem->deleteLater();
191 d->rootItem =
new QQuickItem(
this);
192 d->rootItem->setParentItem(
this);
193 d->rootItem->setImplicitWidth(item->width());
194 d->rootItem->setImplicitHeight(item->height());
196 item->setParent(d->rootItem);
197 item->setParentItem(d->rootItem);
199 setImplicitWidth(d->rootItem->width());
200 setImplicitHeight(d->rootItem->height());
202 updateAnimationProperties();
203 updateRootItemScale();
206 static int freezeTime = qEnvironmentVariableIntValue(
"QT_QUICKVECTORIMAGE_FREEZE");
207 if (freezeTime != 0) {
210 animations()->setPaused(
true);
211 const QList<QQuickAbstractAnimation *> anims = d->rootItem->findChildren<QQuickAbstractAnimation *>();
212 for (QQuickAbstractAnimation *anim : anims) {
213 if (anim->group() ==
nullptr)
214 anim->setCurrentTime(freezeTime);
219 d->incubator->disconnect(
this);
220 d->incubator->deleteLater();
221 d->incubator =
nullptr;
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245QQuickVectorImage::QQuickVectorImage(QQuickItem *parent)
246 : QQuickItem(*(
new QQuickVectorImagePrivate), parent)
248 setFlag(QQuickItem::ItemHasContents,
true);
250 QObject::connect(
this, &QQuickItem::widthChanged,
this, &QQuickVectorImage::updateRootItemScale);
251 QObject::connect(
this, &QQuickItem::heightChanged,
this, &QQuickVectorImage::updateRootItemScale);
252 QObject::connect(
this, &QQuickVectorImage::fillModeChanged,
this, &QQuickVectorImage::updateRootItemScale);
255QQuickVectorImage::~QQuickVectorImage()
257 Q_D(QQuickVectorImage);
260 d->incubator =
nullptr;
264
265
266
267
268
269
270
271
272QUrl QQuickVectorImage::source()
const
274 Q_D(
const QQuickVectorImage);
275 return d->sourceFile;
278void QQuickVectorImage::setSource(
const QUrl &source)
280 Q_D(QQuickVectorImage);
281 d->setSource(source);
284void QQuickVectorImage::updateRootItemScale()
286 Q_D(QQuickVectorImage);
288 if (d->rootItem ==
nullptr
289 || qFuzzyIsNull(d->rootItem->width())
290 || qFuzzyIsNull(d->rootItem->height())) {
294 auto xformProp = d->rootItem->transform();
295 QQuickScale *scaleTransform =
nullptr;
296 if (xformProp.count(&xformProp) == 0) {
297 scaleTransform =
new QQuickScale;
298 scaleTransform->setParent(d->rootItem);
299 xformProp.append(&xformProp, scaleTransform);
301 scaleTransform = qobject_cast<QQuickScale *>(xformProp.at(&xformProp, 0));
304 if (scaleTransform !=
nullptr) {
305 qreal xScale = width() / d->rootItem->width();
306 qreal yScale = height() / d->rootItem->height();
308 switch (d->fillMode) {
309 case QQuickVectorImage::NoResize:
310 xScale = yScale = 1.0;
312 case QQuickVectorImage::PreserveAspectFit:
313 xScale = yScale = qMin(xScale, yScale);
315 case QQuickVectorImage::PreserveAspectCrop:
316 xScale = yScale = qMax(xScale, yScale);
318 case QQuickVectorImage::Stretch:
323 scaleTransform->setXScale(xScale);
324 scaleTransform->setYScale(yScale);
328void QQuickVectorImage::updateAnimationProperties()
330 Q_D(QQuickVectorImage);
331 if (Q_UNLIKELY(d->rootItem ==
nullptr || d->rootItem->childItems().isEmpty()))
334 QQuickItem *childItem = d->rootItem->childItems().first();
335 if (Q_LIKELY(d->animations !=
nullptr)) {
336 if (
auto *root = qobject_cast<QQuickAnimationRootItem *>(childItem)) {
337 root->setLoops(d->animations->loops());
338 root->setPaused(d->animations->paused());
340 childItem->setProperty(
"loops", d->animations->loops());
341 childItem->setProperty(
"paused", d->animations->paused());
346QQuickVectorImageAnimations *QQuickVectorImage::animations()
348 Q_D(QQuickVectorImage);
349 if (d->animations ==
nullptr) {
350 d->animations =
new QQuickVectorImageAnimations;
351 QQml_setParent_noEvent(d->animations,
this);
352 QObject::connect(d->animations, &QQuickVectorImageAnimations::loopsChanged,
this, &QQuickVectorImage::updateAnimationProperties);
353 QObject::connect(d->animations, &QQuickVectorImageAnimations::pausedChanged,
this, &QQuickVectorImage::updateAnimationProperties);
356 return d->animations;
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
379QQuickVectorImage::FillMode QQuickVectorImage::fillMode()
const
381 Q_D(
const QQuickVectorImage);
385void QQuickVectorImage::setFillMode(FillMode newFillMode)
387 Q_D(QQuickVectorImage);
388 if (d->fillMode == newFillMode)
390 d->fillMode = newFillMode;
391 emit fillModeChanged();
395
396
397
398
399
400
401
402
403
404
405
406
407
409QQuickVectorImage::RendererType QQuickVectorImage::preferredRendererType()
const
411 Q_D(
const QQuickVectorImage);
412 return d->preferredRendererType;
415void QQuickVectorImage::setPreferredRendererType(RendererType newPreferredRendererType)
417 Q_D(QQuickVectorImage);
418 if (d->preferredRendererType == newPreferredRendererType)
420 d->preferredRendererType = newPreferredRendererType;
422 emit preferredRendererTypeChanged();
426
427
428
429
430
431
432
433
434
435
436
437
438
439
441bool QQuickVectorImage::asynchronousShapes()
const
443 Q_D(
const QQuickVectorImage);
444 return d->m_asyncShapes;
447void QQuickVectorImage::setAsynchronousShapes(
bool asynchronous)
449 Q_D(QQuickVectorImage);
450 if (d->m_asyncShapes == asynchronous)
452 d->m_asyncShapes = asynchronous;
453 emit asynchronousShapesChanged();
457
458
459
460
461
462
463
464
465
466
467
469bool QQuickVectorImage::asynchronous()
const
471 Q_D(
const QQuickVectorImage);
472 return d->asynchronous;
475void QQuickVectorImage::setAsynchronous(
bool asynchronous)
477 Q_D(QQuickVectorImage);
478 if (d->asynchronous == asynchronous)
480 d->asynchronous = asynchronous;
481 emit asynchronousChanged();
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500bool QQuickVectorImage::retainWhileLoading()
const
502 Q_D(
const QQuickVectorImage);
503 return d->retainWhileLoading;
506void QQuickVectorImage::setRetainWhileLoading(
bool retainWhileLoading)
508 Q_D(QQuickVectorImage);
509 if (d->retainWhileLoading == retainWhileLoading)
511 d->retainWhileLoading = retainWhileLoading;
512 emit retainWhileLoadingChanged();
516
517
518
519
520
521
522
523
524
525
526QQuickVectorImage::Status QQuickVectorImage::status()
const
528 Q_D(
const QQuickVectorImage);
529 if (d->incubator ==
nullptr) {
530 if (d->rootItem ==
nullptr)
533 return Status::Ready;
536 switch (d->incubator->status()) {
537 case QQmlIncubator::Null:
539 case QQmlIncubator::Loading:
540 return Status::Loading;
541 case QQmlIncubator::Error:
542 return Status::Error;
543 case QQmlIncubator::Ready:
544 return Status::Ready;
547 return Status::Error;
551
552
553
554
555
556
557
558
559
560
561
562
563
564
566bool QQuickVectorImage::assumeTrustedSource()
const
568 Q_D(
const QQuickVectorImage);
569 return d->assumeTrustedSource;
572void QQuickVectorImage::setAssumeTrustedSource(
bool assumeTrustedSource)
574 Q_D(QQuickVectorImage);
575 if (d->assumeTrustedSource == assumeTrustedSource)
577 d->assumeTrustedSource = assumeTrustedSource;
579 emit assumeTrustedSourceChanged();
583
584
585
586
587
588
589
591QQuickItem *QQuickVectorImage::generatedItem()
const
593 Q_D(
const QQuickVectorImage);
594 return d->rootItem ? d->rootItem->childItems().value(0) :
nullptr;
597void QQuickVectorImage::componentComplete()
599 Q_D(QQuickVectorImage);
600 QQuickItem::componentComplete();
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622int QQuickVectorImageAnimations::loops()
const
627void QQuickVectorImageAnimations::setLoops(
int loops)
629 if (m_loops == loops)
635bool QQuickVectorImageAnimations::paused()
const
640void QQuickVectorImageAnimations::setPaused(
bool paused)
642 if (m_paused == paused)
645 emit pausedChanged();
648void QQuickVectorImageAnimations::restart()
650 QQuickVectorImage *parentVectorImage = qobject_cast<QQuickVectorImage *>(parent());
651 if (Q_UNLIKELY(parentVectorImage ==
nullptr)) {
652 qCWarning(lcQuickVectorImage) << Q_FUNC_INFO <<
"Parent is not a VectorImage";
656 QQuickVectorImagePrivate *d = QQuickVectorImagePrivate::get(parentVectorImage);
658 if (Q_UNLIKELY(d->rootItem ==
nullptr || d->rootItem->childItems().isEmpty()))
661 QQuickItem *childItem = d->rootItem->childItems().first();
662 QMetaObject::invokeMethod(childItem,
"restart");
667#include <moc_qquickvectorimage_p.cpp>
void setSource(const QUrl &source)
\qmlmodule QtQuick.VectorImage \title Qt Quick Vector Image QML Types
QQuickVectorImageIncubator * incubator
#define QQuickVectorImageFormatsPluginFactory_iid