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>
22using namespace Qt::StringLiterals;
26 QLatin1String(
"/vectorimageformats"), Qt::CaseInsensitive))
28bool QQuickVectorImagePrivate::useQmlGenerator()
30 Q_Q(QQuickVectorImage);
31 static const bool val = !qEnvironmentVariableIsSet(
"QT_QUICKVECTORIMAGE_USE_ITEM_GENERATOR");
32 const bool useNonDefaultGenerator = q->property(
"_qt_usenondefaultgenerator").toBool();
33 return useNonDefaultGenerator ? !val : val;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
63void QQuickVectorImagePrivate::setSource(
const QUrl &source)
65 Q_Q(QQuickVectorImage);
66 if (imageSource.source() == source)
69 imageSource.setSource(source);
71 emit q->sourceChanged();
74void QQuickVectorImagePrivate::setSourceData(
const QByteArray &data)
76 imageSource.setData(data);
80void QQuickVectorImagePrivate::loadFile()
82 Q_Q(QQuickVectorImage);
84 if (!q->isComponentComplete())
87 QQmlContext *ctx = qmlContext(q);
88 imageSource.resolveLocalFileName(ctx);
90 if (rootItem && (!retainWhileLoading || imageSource.isEmpty())) {
91 rootItem->deleteLater();
93 emit q->generatedItemChanged();
94 if (incubator ==
nullptr)
95 emit q->statusChanged();
98 if (imageSource.isEmpty())
101 if (incubator !=
nullptr) {
104 QObject *obj = incubator->object();
107 incubator->disconnect(q);
108 incubator->deleteLater();
111 if (pendingRootItem !=
nullptr) {
112 delete pendingRootItem;
113 pendingRootItem =
nullptr;
116 QQuickVectorImageGenerator::GeneratorFlags flags;
117 if (preferredRendererType == QQuickVectorImage::CurveRenderer)
118 flags.setFlag(QQuickVectorImageGenerator::CurveRenderer);
119 if (assumeTrustedSource)
120 flags.setFlag(QQuickVectorImageGenerator::AssumeTrustedSource);
122 flags.setFlag(QQuickVectorImageGenerator::AsyncShapes);
124 flags.setFlag(QQuickVectorImageGenerator::AsynchronousLoading);
126 if (useQmlGenerator()) {
127 QQmlIncubator::IncubationMode mode =
128 asynchronous ? QQmlIncubator::Asynchronous : QQmlIncubator::Synchronous;
130 if (!context || context->engine() != qmlContext(q)->engine())
131 context.reset(
new QQmlContext(qmlContext(q)->engine()));
133 incubator =
new QQuickVectorImageIncubator(mode, context.get(), q);
134 QObject::connect(incubator, &QQuickVectorImageIncubator::statusUpdated, q,
135 &QQuickVectorImage::updateItem);
136 incubator->start(imageSource, flags);
138 QQuickItemGenerator gen(imageSource, flags, qmlContext(q));
140 bool generatedWithPlugin =
false;
141 if (flags.testFlag(QQuickVectorImageGenerator::AssumeTrustedSource)) {
142 QFactoryLoader *loader = itemGenPluginLoader();
143 const qsizetype count = loader->keyMap().size();
144 for (qsizetype i = 0; i < count && !generatedWithPlugin; ++i) {
145 QQuickVectorImagePlugin *plugin =
146 qobject_cast<QQuickVectorImagePlugin *>(loader->instance(i));
147 if (plugin !=
nullptr) {
148 std::unique_ptr<QQuickVectorImagePluginGenerator> pluginGen(
149 plugin->createGenerator(imageSource));
150 if (pluginGen !=
nullptr)
151 generatedWithPlugin = pluginGen->generate(&gen);
156 if (!generatedWithPlugin)
159 if (gen.errorState() != QQuickVectorImageGenerator::NoError) {
160 qCWarning(lcQuickVectorImage)
161 <<
"QQuickItemGenerator: failed to generate" << imageSource
162 <<
"(errorState:" << gen.errorState() <<
")";
164 pendingRootItem = gen.takeRootItem();
170void QQuickVectorImage::updateItem()
172 Q_D(QQuickVectorImage);
174 const QQuickItem *oldGenItem = generatedItem();
175 auto emitter = qScopeGuard([&] {
176 if (generatedItem() != oldGenItem)
177 emit generatedItemChanged();
178 emit statusChanged();
181 QQuickItem *item =
nullptr;
182 if (d->incubator !=
nullptr) {
183 if (d->incubator->object() ==
nullptr || !d->incubator->isReady())
185 item = qobject_cast<QQuickItem *>(d->incubator->object());
186 if (item ==
nullptr) {
187 qCWarning(lcQuickVectorImage)
188 <<
"QQuickVectorImage::updateItem: Root item not a QQuickItem:"
189 << d->incubator->errors();
193 item = d->pendingRootItem;
194 d->pendingRootItem =
nullptr;
199 if (d->rootItem !=
nullptr)
200 d->rootItem->deleteLater();
202 d->rootItem =
new QQuickItem(
this);
203 d->rootItem->setParentItem(
this);
204 d->rootItem->setImplicitWidth(item->width());
205 d->rootItem->setImplicitHeight(item->height());
207 item->setParent(d->rootItem);
208 item->setParentItem(d->rootItem);
210 setImplicitWidth(d->rootItem->width());
211 setImplicitHeight(d->rootItem->height());
213 updateAnimationProperties();
214 updateRootItemScale();
217 static int freezeTime = qEnvironmentVariableIntValue(
"QT_QUICKVECTORIMAGE_FREEZE");
218 if (freezeTime != 0) {
221 animations()->setPaused(
true);
222 const QList<QQuickAbstractAnimation *> anims = d->rootItem->findChildren<QQuickAbstractAnimation *>();
223 for (QQuickAbstractAnimation *anim : anims) {
224 if (anim->group() ==
nullptr)
225 anim->setCurrentTime(freezeTime);
230 QQuickVectorImageIncubatorPrivate *dd = QQuickVectorImageIncubatorPrivate::get(d->incubator);
231 auto componentGuard = dd->takeComponentGuard();
232 if (!componentGuard.isNull()) {
233 Q_ASSERT(componentGuard.component() ==
nullptr);
234 connect(d->rootItem, &QObject::destroyed, d->rootItem,
235 [componentGuard = std::move(componentGuard)]() {
237 Q_UNUSED(componentGuard);
241 d->incubator->disconnect(
this);
242 d->incubator->deleteLater();
243 d->incubator =
nullptr;
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267QQuickVectorImage::QQuickVectorImage(QQuickItem *parent)
268 : QQuickItem(*(
new QQuickVectorImagePrivate), parent)
270 setFlag(QQuickItem::ItemHasContents,
true);
272 QObject::connect(
this, &QQuickItem::widthChanged,
this, &QQuickVectorImage::updateRootItemScale);
273 QObject::connect(
this, &QQuickItem::heightChanged,
this, &QQuickVectorImage::updateRootItemScale);
274 QObject::connect(
this, &QQuickVectorImage::fillModeChanged,
this, &QQuickVectorImage::updateRootItemScale);
277QQuickVectorImage::~QQuickVectorImage()
279 Q_D(QQuickVectorImage);
282 d->incubator =
nullptr;
286
287
288
289
290
291
292
293
294QUrl QQuickVectorImage::source()
const
296 Q_D(
const QQuickVectorImage);
297 return d->imageSource.source();
300void QQuickVectorImage::setSource(
const QUrl &source)
302 Q_D(QQuickVectorImage);
303 d->setSource(source);
306void QQuickVectorImage::updateRootItemScale()
308 Q_D(QQuickVectorImage);
310 if (d->rootItem ==
nullptr
311 || qFuzzyIsNull(d->rootItem->width())
312 || qFuzzyIsNull(d->rootItem->height())) {
316 auto xformProp = d->rootItem->transform();
317 QQuickScale *scaleTransform =
nullptr;
318 if (xformProp.count(&xformProp) == 0) {
319 scaleTransform =
new QQuickScale;
320 scaleTransform->setParent(d->rootItem);
321 xformProp.append(&xformProp, scaleTransform);
323 scaleTransform = qobject_cast<QQuickScale *>(xformProp.at(&xformProp, 0));
326 if (scaleTransform !=
nullptr) {
327 qreal xScale = width() / d->rootItem->width();
328 qreal yScale = height() / d->rootItem->height();
330 switch (d->fillMode) {
331 case QQuickVectorImage::NoResize:
332 xScale = yScale = 1.0;
334 case QQuickVectorImage::PreserveAspectFit:
335 xScale = yScale = qMin(xScale, yScale);
337 case QQuickVectorImage::PreserveAspectCrop:
338 xScale = yScale = qMax(xScale, yScale);
340 case QQuickVectorImage::Stretch:
345 scaleTransform->setXScale(xScale);
346 scaleTransform->setYScale(yScale);
350void QQuickVectorImage::updateAnimationProperties()
352 Q_D(QQuickVectorImage);
353 if (Q_UNLIKELY(d->rootItem ==
nullptr || d->rootItem->childItems().isEmpty()))
356 QQuickItem *childItem = d->rootItem->childItems().first();
357 if (Q_LIKELY(d->animations !=
nullptr)) {
358 if (
auto *root = qobject_cast<QQuickAnimationRootItem *>(childItem)) {
359 root->setLoops(d->animations->loops());
360 root->setPaused(d->animations->paused());
362 childItem->setProperty(
"loops", d->animations->loops());
363 childItem->setProperty(
"paused", d->animations->paused());
368QQuickVectorImageAnimations *QQuickVectorImage::animations()
370 Q_D(QQuickVectorImage);
371 if (d->animations ==
nullptr) {
372 d->animations =
new QQuickVectorImageAnimations;
373 QQml_setParent_noEvent(d->animations,
this);
374 QObject::connect(d->animations, &QQuickVectorImageAnimations::loopsChanged,
this, &QQuickVectorImage::updateAnimationProperties);
375 QObject::connect(d->animations, &QQuickVectorImageAnimations::pausedChanged,
this, &QQuickVectorImage::updateAnimationProperties);
378 return d->animations;
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
401QQuickVectorImage::FillMode QQuickVectorImage::fillMode()
const
403 Q_D(
const QQuickVectorImage);
407void QQuickVectorImage::setFillMode(FillMode newFillMode)
409 Q_D(QQuickVectorImage);
410 if (d->fillMode == newFillMode)
412 d->fillMode = newFillMode;
413 emit fillModeChanged();
417
418
419
420
421
422
423
424
425
426
427
428
429
431QQuickVectorImage::RendererType QQuickVectorImage::preferredRendererType()
const
433 Q_D(
const QQuickVectorImage);
434 return d->preferredRendererType;
437void QQuickVectorImage::setPreferredRendererType(RendererType newPreferredRendererType)
439 Q_D(QQuickVectorImage);
440 if (d->preferredRendererType == newPreferredRendererType)
442 d->preferredRendererType = newPreferredRendererType;
444 emit preferredRendererTypeChanged();
448
449
450
451
452
453
454
455
456
457
458
459
460
461
463bool QQuickVectorImage::asynchronousShapes()
const
465 Q_D(
const QQuickVectorImage);
466 return d->m_asyncShapes;
469void QQuickVectorImage::setAsynchronousShapes(
bool asynchronous)
471 Q_D(QQuickVectorImage);
472 if (d->m_asyncShapes == asynchronous)
474 d->m_asyncShapes = asynchronous;
475 emit asynchronousShapesChanged();
479
480
481
482
483
484
485
486
487
488
489
491bool QQuickVectorImage::asynchronous()
const
493 Q_D(
const QQuickVectorImage);
494 return d->asynchronous;
497void QQuickVectorImage::setAsynchronous(
bool asynchronous)
499 Q_D(QQuickVectorImage);
500 if (d->asynchronous == asynchronous)
502 d->asynchronous = asynchronous;
503 emit asynchronousChanged();
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522bool QQuickVectorImage::retainWhileLoading()
const
524 Q_D(
const QQuickVectorImage);
525 return d->retainWhileLoading;
528void QQuickVectorImage::setRetainWhileLoading(
bool retainWhileLoading)
530 Q_D(QQuickVectorImage);
531 if (d->retainWhileLoading == retainWhileLoading)
533 d->retainWhileLoading = retainWhileLoading;
534 emit retainWhileLoadingChanged();
538
539
540
541
542
543
544
545
546
547
548QQuickVectorImage::Status QQuickVectorImage::status()
const
550 Q_D(
const QQuickVectorImage);
551 if (d->incubator ==
nullptr) {
552 if (d->rootItem !=
nullptr)
553 return Status::Ready;
554 else if (!isComponentComplete() || d->imageSource.isEmpty())
557 return Status::Error;
560 switch (d->incubator->status()) {
561 case QQmlIncubator::Null:
563 case QQmlIncubator::Loading:
564 return Status::Loading;
565 case QQmlIncubator::Error:
566 return Status::Error;
567 case QQmlIncubator::Ready:
568 return Status::Ready;
571 return Status::Error;
575
576
577
578
579
580
581
582
583
584
585
586
587
588
590bool QQuickVectorImage::assumeTrustedSource()
const
592 Q_D(
const QQuickVectorImage);
593 return d->assumeTrustedSource;
596void QQuickVectorImage::setAssumeTrustedSource(
bool assumeTrustedSource)
598 Q_D(QQuickVectorImage);
599 if (d->assumeTrustedSource == assumeTrustedSource)
601 d->assumeTrustedSource = assumeTrustedSource;
603 emit assumeTrustedSourceChanged();
607
608
609
610
611
612
613
615QQuickItem *QQuickVectorImage::generatedItem()
const
617 Q_D(
const QQuickVectorImage);
618 return d->rootItem ? d->rootItem->childItems().value(0) :
nullptr;
621void QQuickVectorImage::componentComplete()
623 Q_D(QQuickVectorImage);
624 QQuickItem::componentComplete();
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646int QQuickVectorImageAnimations::loops()
const
651void QQuickVectorImageAnimations::setLoops(
int loops)
653 if (m_loops == loops)
659bool QQuickVectorImageAnimations::paused()
const
664void QQuickVectorImageAnimations::setPaused(
bool paused)
666 if (m_paused == paused)
669 emit pausedChanged();
672void QQuickVectorImageAnimations::restart()
674 QQuickVectorImage *parentVectorImage = qobject_cast<QQuickVectorImage *>(parent());
675 if (Q_UNLIKELY(parentVectorImage ==
nullptr)) {
676 qCWarning(lcQuickVectorImage) << Q_FUNC_INFO <<
"Parent is not a VectorImage";
680 QQuickVectorImagePrivate *d = QQuickVectorImagePrivate::get(parentVectorImage);
682 if (Q_UNLIKELY(d->rootItem ==
nullptr || d->rootItem->childItems().isEmpty()))
685 QQuickItem *childItem = d->rootItem->childItems().first();
686 QMetaObject::invokeMethod(childItem,
"restart");
691#include <moc_qquickvectorimage_p.cpp>
Q_GLOBAL_STATIC_WITH_ARGS(PermissionStatusHash, g_permissionStatusHash,({ { qMetaTypeId< QCameraPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QMicrophonePermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QBluetoothPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QContactsPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QCalendarPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QLocationPermission >(), Qt::PermissionStatus::Undetermined } }))
#define QQuickVectorImageFormatsPluginFactory_iid