4#include <QtCore/qurl.h>
5#include <QtCore/QScopeGuard>
11#include <QtQuickVectorImageGenerator/private/qquickitemgenerator_p.h>
12#include <QtQuickVectorImageGenerator/private/qquickvectorimageglobal_p.h>
13#include <QtQuickVectorImageGenerator/private/qquickanimationrootitem_p.h>
14#include <QtCore/private/qfactoryloader_p.h>
15#include <QtCore/qloggingcategory.h>
17#include <private/qquicktranslate_p.h>
18#include <private/qquickanimation_p.h>
22Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, itemGenPluginLoader,
24 QLatin1String(
"/vectorimageformats"), Qt::CaseInsensitive))
26static bool useQmlGenerator()
28 static const bool val = !qEnvironmentVariableIsSet(
"QT_QUICKVECTORIMAGE_USE_ITEM_GENERATOR");
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
59void QQuickVectorImagePrivate::setSource(
const QUrl &source)
61 Q_Q(QQuickVectorImage);
62 if (imageSource.source() == source)
65 imageSource.setSource(source);
67 emit q->sourceChanged();
70void QQuickVectorImagePrivate::setSourceData(
const QByteArray &data)
72 imageSource.setData(data);
76void QQuickVectorImagePrivate::loadFile()
78 Q_Q(QQuickVectorImage);
80 if (!q->isComponentComplete())
83 QQmlContext *ctx = qmlContext(q);
84 imageSource.resolveLocalFileName(ctx);
86 if (rootItem && (!retainWhileLoading || imageSource.isEmpty())) {
87 rootItem->deleteLater();
89 emit q->generatedItemChanged();
90 if (incubator ==
nullptr)
91 emit q->statusChanged();
94 if (imageSource.isEmpty())
97 if (incubator !=
nullptr) {
100 QObject *obj = incubator->object();
103 incubator->disconnect(q);
104 incubator->deleteLater();
107 if (pendingRootItem !=
nullptr) {
108 delete pendingRootItem;
109 pendingRootItem =
nullptr;
112 QQuickVectorImageGenerator::GeneratorFlags flags;
113 if (preferredRendererType == QQuickVectorImage::CurveRenderer)
114 flags.setFlag(QQuickVectorImageGenerator::CurveRenderer);
115 if (assumeTrustedSource)
116 flags.setFlag(QQuickVectorImageGenerator::AssumeTrustedSource);
118 flags.setFlag(QQuickVectorImageGenerator::AsyncShapes);
120 flags.setFlag(QQuickVectorImageGenerator::AsynchronousLoading);
122 if (useQmlGenerator()) {
123 QQmlIncubator::IncubationMode mode =
124 asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::Synchronous;
126 if (!context || context->engine() != qmlContext(q)->engine())
127 context.reset(
new QQmlContext(qmlContext(q)->engine()));
129 incubator =
new QQuickVectorImageIncubator(mode, context.get(), q);
130 QObject::connect(incubator, &QQuickVectorImageIncubator::statusUpdated, q,
131 &QQuickVectorImage::updateItem);
132 incubator->start(imageSource, flags);
134 QQuickItemGenerator gen(imageSource, flags, qmlContext(q));
136 bool generatedWithPlugin =
false;
137 if (flags.testFlag(QQuickVectorImageGenerator::AssumeTrustedSource)) {
138 QFactoryLoader *loader = itemGenPluginLoader();
139 const qsizetype count = loader->keyMap().size();
140 for (qsizetype i = 0; i < count && !generatedWithPlugin; ++i) {
141 QQuickVectorImagePlugin *plugin =
142 qobject_cast<QQuickVectorImagePlugin *>(loader->instance(i));
143 if (plugin !=
nullptr) {
144 std::unique_ptr<QQuickVectorImagePluginGenerator> pluginGen(
145 plugin->createGenerator(imageSource));
146 if (pluginGen !=
nullptr)
147 generatedWithPlugin = pluginGen->generate(&gen);
152 if (!generatedWithPlugin)
155 if (gen.errorState() != QQuickVectorImageGenerator::NoError) {
156 qCWarning(lcQuickVectorImage)
157 <<
"QQuickItemGenerator: failed to generate" << imageSource
158 <<
"(errorState:" << gen.errorState() <<
")";
160 pendingRootItem = gen.takeRootItem();
166void QQuickVectorImage::updateItem()
168 Q_D(QQuickVectorImage);
170 const QQuickItem *oldGenItem = generatedItem();
171 auto emitter = qScopeGuard([&] {
172 if (generatedItem() != oldGenItem)
173 emit generatedItemChanged();
174 emit statusChanged();
177 QQuickItem *item =
nullptr;
178 if (d->incubator !=
nullptr) {
179 if (d->incubator->object() ==
nullptr || !d->incubator->isReady())
181 item = qobject_cast<QQuickItem *>(d->incubator->object());
182 if (item ==
nullptr) {
183 qCWarning(lcQuickVectorImage)
184 <<
"QQuickVectorImage::updateItem: Root item not a QQuickItem:"
185 << d->incubator->errors();
189 item = d->pendingRootItem;
190 d->pendingRootItem =
nullptr;
195 if (d->rootItem !=
nullptr)
196 d->rootItem->deleteLater();
198 d->rootItem =
new QQuickItem(
this);
199 d->rootItem->setParentItem(
this);
200 d->rootItem->setImplicitWidth(item->width());
201 d->rootItem->setImplicitHeight(item->height());
203 item->setParent(d->rootItem);
204 item->setParentItem(d->rootItem);
206 setImplicitWidth(d->rootItem->width());
207 setImplicitHeight(d->rootItem->height());
209 updateAnimationProperties();
210 updateRootItemScale();
213 static int freezeTime = qEnvironmentVariableIntValue(
"QT_QUICKVECTORIMAGE_FREEZE");
214 if (freezeTime != 0) {
217 animations()->setPaused(
true);
218 const QList<QQuickAbstractAnimation *> anims = d->rootItem->findChildren<QQuickAbstractAnimation *>();
219 for (QQuickAbstractAnimation *anim : anims) {
220 if (anim->group() ==
nullptr)
221 anim->setCurrentTime(freezeTime);
226 QQuickVectorImageIncubatorPrivate *dd = QQuickVectorImageIncubatorPrivate::get(d->incubator);
227 auto componentGuard = dd->takeComponentGuard();
228 if (!componentGuard.isNull()) {
229 Q_ASSERT(componentGuard.component() ==
nullptr);
230 connect(d->rootItem, &QObject::destroyed, d->rootItem,
231 [componentGuard = std::move(componentGuard)]() {
233 Q_UNUSED(componentGuard);
237 d->incubator->disconnect(
this);
238 d->incubator->deleteLater();
239 d->incubator =
nullptr;
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263QQuickVectorImage::QQuickVectorImage(QQuickItem *parent)
264 : QQuickItem(*(
new QQuickVectorImagePrivate), parent)
266 setFlag(QQuickItem::ItemHasContents,
true);
268 QObject::connect(
this, &QQuickItem::widthChanged,
this, &QQuickVectorImage::updateRootItemScale);
269 QObject::connect(
this, &QQuickItem::heightChanged,
this, &QQuickVectorImage::updateRootItemScale);
270 QObject::connect(
this, &QQuickVectorImage::fillModeChanged,
this, &QQuickVectorImage::updateRootItemScale);
273QQuickVectorImage::~QQuickVectorImage()
275 Q_D(QQuickVectorImage);
278 d->incubator =
nullptr;
282
283
284
285
286
287
288
289
290QUrl QQuickVectorImage::source()
const
292 Q_D(
const QQuickVectorImage);
293 return d->imageSource.source();
296void QQuickVectorImage::setSource(
const QUrl &source)
298 Q_D(QQuickVectorImage);
299 d->setSource(source);
302void QQuickVectorImage::updateRootItemScale()
304 Q_D(QQuickVectorImage);
306 if (d->rootItem ==
nullptr
307 || qFuzzyIsNull(d->rootItem->width())
308 || qFuzzyIsNull(d->rootItem->height())) {
312 auto xformProp = d->rootItem->transform();
313 QQuickScale *scaleTransform =
nullptr;
314 if (xformProp.count(&xformProp) == 0) {
315 scaleTransform =
new QQuickScale;
316 scaleTransform->setParent(d->rootItem);
317 xformProp.append(&xformProp, scaleTransform);
319 scaleTransform = qobject_cast<QQuickScale *>(xformProp.at(&xformProp, 0));
322 if (scaleTransform !=
nullptr) {
323 qreal xScale = width() / d->rootItem->width();
324 qreal yScale = height() / d->rootItem->height();
326 switch (d->fillMode) {
327 case QQuickVectorImage::NoResize:
328 xScale = yScale = 1.0;
330 case QQuickVectorImage::PreserveAspectFit:
331 xScale = yScale = qMin(xScale, yScale);
333 case QQuickVectorImage::PreserveAspectCrop:
334 xScale = yScale = qMax(xScale, yScale);
336 case QQuickVectorImage::Stretch:
341 scaleTransform->setXScale(xScale);
342 scaleTransform->setYScale(yScale);
346void QQuickVectorImage::updateAnimationProperties()
348 Q_D(QQuickVectorImage);
349 if (Q_UNLIKELY(d->rootItem ==
nullptr || d->rootItem->childItems().isEmpty()))
352 QQuickItem *childItem = d->rootItem->childItems().first();
353 if (Q_LIKELY(d->animations !=
nullptr)) {
354 if (
auto *root = qobject_cast<QQuickAnimationRootItem *>(childItem)) {
355 root->setLoops(d->animations->loops());
356 root->setPaused(d->animations->paused());
358 childItem->setProperty(
"loops", d->animations->loops());
359 childItem->setProperty(
"paused", d->animations->paused());
364QQuickVectorImageAnimations *QQuickVectorImage::animations()
366 Q_D(QQuickVectorImage);
367 if (d->animations ==
nullptr) {
368 d->animations =
new QQuickVectorImageAnimations;
369 QQml_setParent_noEvent(d->animations,
this);
370 QObject::connect(d->animations, &QQuickVectorImageAnimations::loopsChanged,
this, &QQuickVectorImage::updateAnimationProperties);
371 QObject::connect(d->animations, &QQuickVectorImageAnimations::pausedChanged,
this, &QQuickVectorImage::updateAnimationProperties);
374 return d->animations;
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
397QQuickVectorImage::FillMode QQuickVectorImage::fillMode()
const
399 Q_D(
const QQuickVectorImage);
403void QQuickVectorImage::setFillMode(FillMode newFillMode)
405 Q_D(QQuickVectorImage);
406 if (d->fillMode == newFillMode)
408 d->fillMode = newFillMode;
409 emit fillModeChanged();
413
414
415
416
417
418
419
420
421
422
423
424
425
427QQuickVectorImage::RendererType QQuickVectorImage::preferredRendererType()
const
429 Q_D(
const QQuickVectorImage);
430 return d->preferredRendererType;
433void QQuickVectorImage::setPreferredRendererType(RendererType newPreferredRendererType)
435 Q_D(QQuickVectorImage);
436 if (d->preferredRendererType == newPreferredRendererType)
438 d->preferredRendererType = newPreferredRendererType;
440 emit preferredRendererTypeChanged();
444
445
446
447
448
449
450
451
452
453
454
455
456
457
459bool QQuickVectorImage::asynchronousShapes()
const
461 Q_D(
const QQuickVectorImage);
462 return d->m_asyncShapes;
465void QQuickVectorImage::setAsynchronousShapes(
bool asynchronous)
467 Q_D(QQuickVectorImage);
468 if (d->m_asyncShapes == asynchronous)
470 d->m_asyncShapes = asynchronous;
471 emit asynchronousShapesChanged();
475
476
477
478
479
480
481
482
483
484
485
487bool QQuickVectorImage::asynchronous()
const
489 Q_D(
const QQuickVectorImage);
490 return d->asynchronous;
493void QQuickVectorImage::setAsynchronous(
bool asynchronous)
495 Q_D(QQuickVectorImage);
496 if (d->asynchronous == asynchronous)
498 d->asynchronous = asynchronous;
499 emit asynchronousChanged();
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518bool QQuickVectorImage::retainWhileLoading()
const
520 Q_D(
const QQuickVectorImage);
521 return d->retainWhileLoading;
524void QQuickVectorImage::setRetainWhileLoading(
bool retainWhileLoading)
526 Q_D(QQuickVectorImage);
527 if (d->retainWhileLoading == retainWhileLoading)
529 d->retainWhileLoading = retainWhileLoading;
530 emit retainWhileLoadingChanged();
534
535
536
537
538
539
540
541
542
543
544QQuickVectorImage::Status QQuickVectorImage::status()
const
546 Q_D(
const QQuickVectorImage);
547 if (d->incubator ==
nullptr) {
548 if (d->rootItem !=
nullptr)
549 return Status::Ready;
550 else if (!isComponentComplete() || d->imageSource.isEmpty())
553 return Status::Error;
556 switch (d->incubator->status()) {
557 case QQmlIncubator::Null:
559 case QQmlIncubator::Loading:
560 return Status::Loading;
561 case QQmlIncubator::Error:
562 return Status::Error;
563 case QQmlIncubator::Ready:
564 return Status::Ready;
567 return Status::Error;
571
572
573
574
575
576
577
578
579
580
581
582
583
584
586bool QQuickVectorImage::assumeTrustedSource()
const
588 Q_D(
const QQuickVectorImage);
589 return d->assumeTrustedSource;
592void QQuickVectorImage::setAssumeTrustedSource(
bool assumeTrustedSource)
594 Q_D(QQuickVectorImage);
595 if (d->assumeTrustedSource == assumeTrustedSource)
597 d->assumeTrustedSource = assumeTrustedSource;
599 emit assumeTrustedSourceChanged();
603
604
605
606
607
608
609
611QQuickItem *QQuickVectorImage::generatedItem()
const
613 Q_D(
const QQuickVectorImage);
614 return d->rootItem ? d->rootItem->childItems().value(0) :
nullptr;
617void QQuickVectorImage::componentComplete()
619 Q_D(QQuickVectorImage);
620 QQuickItem::componentComplete();
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642int QQuickVectorImageAnimations::loops()
const
647void QQuickVectorImageAnimations::setLoops(
int loops)
649 if (m_loops == loops)
655bool QQuickVectorImageAnimations::paused()
const
660void QQuickVectorImageAnimations::setPaused(
bool paused)
662 if (m_paused == paused)
665 emit pausedChanged();
668void QQuickVectorImageAnimations::restart()
670 QQuickVectorImage *parentVectorImage = qobject_cast<QQuickVectorImage *>(parent());
671 if (Q_UNLIKELY(parentVectorImage ==
nullptr)) {
672 qCWarning(lcQuickVectorImage) << Q_FUNC_INFO <<
"Parent is not a VectorImage";
676 QQuickVectorImagePrivate *d = QQuickVectorImagePrivate::get(parentVectorImage);
678 if (Q_UNLIKELY(d->rootItem ==
nullptr || d->rootItem->childItems().isEmpty()))
681 QQuickItem *childItem = d->rootItem->childItems().first();
682 QMetaObject::invokeMethod(childItem,
"restart");
687#include <moc_qquickvectorimage_p.cpp>
#define QQuickVectorImageFormatsPluginFactory_iid