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
qquickvectorimageincubator.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 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
6#include <QtCore/private/qfactoryloader_p.h>
7#include <QtQml/qqmlcontext.h>
8#include <QtQml/private/qqmlcomponent_p.h>
9#include <QtQml/private/qqmlmetatype_p.h>
10
12
13Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, vectorImagePluginLoader,
14 (QQuickVectorImageFormatsPluginFactory_iid,
15 QLatin1String("/vectorimageformats"),
16 Qt::CaseInsensitive))
17
18void QQuickVectorImageWorker::process()
19{
20 Q_ASSERT(m_generator != nullptr);
21
22 // If we assume trusted source, we try plugins first
23 bool generatedWithPlugin = false;
24 for (const auto &pluginGenerator : std::as_const(m_pluginGenerators)) {
25 if ((generatedWithPlugin = pluginGenerator->generate(m_generator.get())))
26 break;
27 }
28
29 if (!generatedWithPlugin)
30 m_generator->generate();
31
32 emit finished();
33}
34
35QQuickVectorImageIncubator::QQuickVectorImageIncubator(IncubationMode incubationMode,
36 QQmlContext *context,
37 QObject *parent)
38 : QObject(*new QQuickVectorImageIncubatorPrivate, parent)
39 , QQmlIncubator(incubationMode)
40{
41 Q_D(QQuickVectorImageIncubator);
42 d->qmlContext = context;
43}
44
45QQuickVectorImageIncubator::~QQuickVectorImageIncubator()
46{
47 Q_D(QQuickVectorImageIncubator);
48 if (d->workerThread != nullptr && d->workerThread->isRunning()) {
49 d->workerThread->quit();
50 d->workerThread->wait();
51 }
52}
53
54QQmlIncubator::Status QQuickVectorImageIncubator::status() const
55{
56 Q_D(const QQuickVectorImageIncubator);
57 return d->status;
58}
59
60void QQuickVectorImageIncubator::start(const QQuickVectorImageSource &source,
61 QQuickVectorImageGenerator::GeneratorFlags flags)
62{
63 Q_D(QQuickVectorImageIncubator);
64 Q_ASSERT(d->generatorWorker == nullptr);
65 Q_ASSERT(d->workerThread == nullptr);
66
67 d->status = Loading;
68 emit statusUpdated();
69
70 const bool asynchronous = flags.testFlag(QQuickVectorImageGenerator::AsynchronousLoading);
71 if (asynchronous)
72 d->workerThread.reset(new QThread);
73
74 d->generatorWorker.reset(new QQuickVectorImageWorker);
75 d->generatorWorker->createGenerator(source, flags);
76 connect(d->generatorWorker.get(), &QQuickVectorImageWorker::finished,
77 this, &QQuickVectorImageIncubator::generatorFinished);
78
79 if (flags.testFlag(QQuickVectorImageGenerator::AssumeTrustedSource)) {
80 QFactoryLoader *loader = vectorImagePluginLoader();
81
82 const qsizetype count = loader->keyMap().size();
83 for (qsizetype i = 0; i < count; ++i) {
84 QQuickVectorImagePlugin *plugin = qobject_cast<QQuickVectorImagePlugin *>(loader->instance(i));
85 if (plugin != nullptr) {
86 QQuickVectorImagePluginGenerator *pluginGenerator = plugin->createGenerator(source);
87 if (pluginGenerator != nullptr)
88 d->generatorWorker->addPluginGenerator(pluginGenerator);
89 }
90 }
91 }
92
93 if (d->workerThread != nullptr) {
94 d->generatorWorker->moveToThread(d->workerThread.get());
95 d->workerThread->start();
96 }
97
98 // Trigger generating
99 QMetaObject::invokeMethod(d->generatorWorker.get(), &QQuickVectorImageWorker::process, Qt::AutoConnection);
100}
101
102void QQuickVectorImageIncubator::generatorFinished()
103{
104 Q_D(QQuickVectorImageIncubator);
105 Q_ASSERT(d->componentGuard.component() == nullptr);
106 Q_ASSERT(d->generatorWorker != nullptr);
107 Q_ASSERT(d->generatorWorker->generator() != nullptr);
108 Q_ASSERT(d->workerThread == nullptr || d->workerThread->isRunning());
109
110 const QQuickVectorImageGenerator::ErrorState errorState = d->generatorWorker->generator()->errorState();
111 const bool asynchronous = d->generatorWorker->generator()->generatorFlags().testFlag(QQuickVectorImageGenerator::AsynchronousLoading);
112 const QByteArray result = d->generatorWorker->generator()->result();
113
114 d->generatorWorker->disconnect(this);
115 d->generatorWorker.release()->deleteLater();
116
117 if (d->workerThread != nullptr) {
118 d->workerThread->quit();
119 d->workerThread->wait();
120 d->workerThread.reset(nullptr);
121 }
122
123 if (Q_LIKELY(errorState == QQuickVectorImageGenerator::NoError)) {
124 QQmlEngine *engine = d->qmlContext->engine();
125 if (Q_UNLIKELY(engine == nullptr)) {
126 qCWarning(lcQuickVectorImage) << "QQuickVectorImageIncubator::generatorFinished: Requires QML engine";
127 return;
128 }
129
130 d->componentGuard.setComponent(new QQmlComponent(engine));
131 connect(d->componentGuard.component(), &QQmlComponent::statusChanged,
132 this, &QQuickVectorImageIncubator::componentUpdated);
133 if (asynchronous) {
134 QQmlComponentPrivate *cd = QQmlComponentPrivate::get(d->componentGuard.component());
135 cd->setData(result, QUrl{}, QQmlComponent::Asynchronous);
136 emit d->componentGuard.component()->statusChanged(d->componentGuard.component()->status());
137 } else {
138 d->componentGuard.component()->setData(result, QUrl{});
139 }
140 } else {
141 d->status = Error;
142 emit statusUpdated();
143 }
144}
145
146QQuickVectorImageIncubatorPrivate::QmlComponentGuard::~QmlComponentGuard()
147{
148 if (m_component != nullptr)
149 delete takeComponent(); // Updates m_baseCompilationUnit
150
151 if (m_baseCompilationUnit != nullptr) {
152 QQmlMetaType::unregisterInternalCompositeType(m_baseCompilationUnit);
153 m_baseCompilationUnit.reset();
154 }
155}
156
157QQuickVectorImageIncubatorPrivate::QmlComponentGuard QQuickVectorImageIncubatorPrivate::takeComponentGuard()
158{
159 return std::move(componentGuard);
160}
161
162QQmlComponent *QQuickVectorImageIncubatorPrivate::QmlComponentGuard::takeComponent()
163{
164 QQmlComponent *ret = nullptr;
165 if (m_component != nullptr) {
166 ret = m_component.release();
167
168 QQmlComponentPrivate *d = QQmlComponentPrivate::get(ret);
169 if (d->compilationUnit() != nullptr)
170 m_baseCompilationUnit = d->compilationUnit()->baseCompilationUnit();
171 }
172
173 return ret;
174}
175
176void QQuickVectorImageIncubator::componentUpdated()
177{
178 Q_D(QQuickVectorImageIncubator);
179 Q_ASSERT(d->componentGuard.component() != nullptr);
180 Q_ASSERT(d->generatorWorker == nullptr);
181 Q_ASSERT(d->workerThread == nullptr);
182
183 if (!d->componentGuard.component()->isLoading()) {
184 // The component is either ready to create or has an error.
185 // We copy the compilation unit reference before emitting statusUpdated (which triggers
186 // updateItem() in QQuickVectorImage where the component guard is expected to only
187 // carry the compilation unit)
188 QQmlComponent *component = d->componentGuard.takeComponent();
189 if (component->isReady()) {
190 component->create(*this, d->qmlContext);
191 } else {
192 qCWarning(lcQuickVectorImage) << "Component failed to load:"
193 << component->errorString();
194 d->status = Error;
195 emit statusUpdated();
196 }
197
198 component->deleteLater();
199 }
200}
201
202void QQuickVectorImageIncubator::statusChanged(Status status)
203{
204 Q_D(QQuickVectorImageIncubator);
205 if (d->status == status)
206 return;
207 d->status = status;
208 emit statusUpdated();
209}
210
211QT_END_NAMESPACE
Combined button and popup list for selecting options.