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
qqmlengine_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 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#ifndef QQMLENGINE_P_H
5#define QQMLENGINE_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include "qqmlengine.h"
19
20#include <private/qfieldlist_p.h>
21#include <private/qintrusivelist_p.h>
22#include <private/qjsengine_p.h>
23#include <private/qjsvalue_p.h>
24#include <private/qpodvector_p.h>
25#include <private/qqmldirparser_p.h>
26#include <private/qqmlimport_p.h>
27#include <private/qqmlmetatype_p.h>
28#include <private/qqmlnotifier_p.h>
29#include <private/qqmlproperty_p.h>
30#include <private/qqmltypeloader_p.h>
31#include <private/qqmlvaluetype_p.h>
32#include <private/qrecyclepool_p.h>
33#include <private/qv4engine_p.h>
34
35#include <QtQml/qqml.h>
36#include <QtQml/qqmlcontext.h>
37
38#include <QtCore/qlist.h>
39#include <QtCore/qmetaobject.h>
40#include <QtCore/qmutex.h>
41#include <QtCore/qpointer.h>
42#include <QtCore/qproperty.h>
43#include <QtCore/qstack.h>
44#include <QtCore/qstring.h>
45#include <QtCore/qthread.h>
46
47#include <atomic>
48
49QT_BEGIN_NAMESPACE
50
51class QNetworkAccessManager;
53class QQmlIncubator;
54class QQmlMetaObject;
55class QQmlNetworkAccessManagerFactory;
56class QQmlObjectCreator;
57class QQmlProfiler;
59
60// This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
61// The inline method definitions are in qqmljavascriptexpression_p.h
63{
64public:
65 inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *);
66
67 static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e,
68 QQmlEngine *engine);
69 inline void Delete();
70
73};
74
91
93 TriggerList(QQmlJavaScriptExpression *expression)
94 : QPropertyChangeTrigger(expression)
95 {}
96 TriggerList *next = nullptr;
97};
98
99class Q_QML_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
100{
101 Q_DECLARE_PUBLIC(QQmlEngine)
102public:
103 ~QQmlEnginePrivate() override;
104
105 void init();
106 // No mutex protecting baseModulesUninitialized, because use outside QQmlEngine
107 // is just qmlClearTypeRegistrations (which can't be called while an engine exists)
108 static bool baseModulesUninitialized;
109
110 QQmlPropertyCapture *propertyCapture = nullptr;
111
112 QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
113 QRecyclePool<TriggerList> qPropertyTriggerPool;
114
115 QQmlContext *rootContext = nullptr;
116 Q_OBJECT_BINDABLE_PROPERTY(QQmlEnginePrivate, QString, translationLanguage);
117
118#if !QT_CONFIG(qml_debug)
119 static const quintptr profiler = 0;
120#else
121 QQmlProfiler *profiler = nullptr;
122#endif
123
124 bool outputWarningsToMsgLog = true;
125
126 // Bindings that have had errors during startup
127 QQmlDelayedError *erroredBindings = nullptr;
128 int inProgressCreations = 0;
129
130#if QT_CONFIG(qml_worker_script)
131 QThread *workerScriptEngine = nullptr;
132#endif
133
134 QUrl baseUrl;
135
136 QQmlObjectCreator *activeObjectCreator = nullptr;
137
138 mutable QRecursiveMutex imageProviderMutex;
139 QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
140 QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const;
141
142 int scarceResourcesRefCount = 0;
143 void referenceScarceResources();
144 void dereferenceScarceResources();
145
146 QString offlineStoragePath;
147
148 // Unfortunate workaround to avoid a circular dependency between
149 // qqmlengine_p.h and qqmlincubator_p.h
150 struct Incubator {
151 QIntrusiveListNode next;
152 };
153 QIntrusiveList<Incubator, &Incubator::next> incubatorList;
154 unsigned int incubatorCount = 0;
155 QQmlIncubationController *incubationController = nullptr;
156 void incubate(QQmlIncubator &, const QQmlRefPointer<QQmlContextData> &);
157
158 // These methods may be called from any thread
159 QString offlineStorageDatabaseDirectory() const;
160
161 template <typename T>
162 T singletonInstance(const QQmlType &type);
163
164 void sendQuit();
165 void sendExit(int retCode = 0);
166 void warning(const QQmlError &);
167 void warning(const QList<QQmlError> &);
168 static void warning(QQmlEngine *, const QQmlError &);
169 static void warning(QQmlEngine *, const QList<QQmlError> &);
170 static void warning(QQmlEnginePrivate *, const QQmlError &);
171 static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
172
173 inline static QQmlEnginePrivate *get(QQmlEngine *e);
174 inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
175 inline static QQmlEngine *get(QQmlEnginePrivate *p);
176 inline static const QQmlEngine *get(const QQmlEnginePrivate *p);
177 inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e);
178
179 inline static QQmlEnginePrivate *get(QQmlContext *c);
180 inline static QQmlEnginePrivate *get(const QQmlRefPointer<QQmlContextData> &c);
181
182 static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages);
183
184 static bool designerMode();
185 static void activateDesignerMode();
186
187 static std::atomic<bool> qml_debugging_enabled;
188
189 QQmlGadgetPtrWrapper *valueTypeInstance(QMetaType type)
190 {
191 int typeIndex = type.id();
192 auto it = cachedValueTypeInstances.constFind(typeIndex);
193 if (it != cachedValueTypeInstances.cend())
194 return *it;
195
196 if (QQmlValueType *valueType = QQmlMetaType::valueType(type)) {
197 QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType);
198 cachedValueTypeInstances.insert(typeIndex, instance);
199 return instance;
200 }
201
202 return nullptr;
203 }
204
205 void executeRuntimeFunction(const QUrl &url, qsizetype functionIndex, QObject *thisObject,
206 int argc = 0, void **args = nullptr, QMetaType *types = nullptr);
207 void executeRuntimeFunction(const QV4::ExecutableCompilationUnit *unit, qsizetype functionIndex,
208 QObject *thisObject, int argc = 0, void **args = nullptr,
209 QMetaType *types = nullptr);
210 QV4::ExecutableCompilationUnit *compilationUnitFromUrl(const QUrl &url);
211 QQmlRefPointer<QQmlContextData>
212 createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
213 const QQmlRefPointer<QQmlContextData> &parentContext,
214 int subComponentIndex, bool isComponentRoot);
215 static void setInternalContext(QObject *This, const QQmlRefPointer<QQmlContextData> &context,
216 QQmlContextData::QmlObjectKind kind)
217 {
218 Q_ASSERT(This);
219 QQmlData *ddata = QQmlData::get(This, /*create*/ true);
220 // NB: copied from QQmlObjectCreator::createInstance()
221 //
222 // the if-statement logic to determine the kind is:
223 // if (static_cast<quint32>(index) == 0 || ddata->rootObjectInCreation || isInlineComponent)
224 // then QQmlContextData::DocumentRoot. here, we pass this through qmltc
225 context->installContext(ddata, kind);
226 Q_ASSERT(qmlEngine(This));
227 }
228
229private:
230 class SingletonInstances : private QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>
231 {
232 public:
233 void convertAndInsert(
234 QV4::ExecutionEngine *engine, const QQmlType::SingletonInstanceInfo::ConstPtr &type,
235 QJSValue *value)
236 {
237 QJSValuePrivate::manageStringOnV4Heap(engine, value);
238 insert(type, *value);
239 }
240
241 void clear()
242 {
243 const auto canDelete = [](QObject *instance, const auto &siinfo) -> bool {
244 if (!instance)
245 return false;
246
247 if (!siinfo->url.isEmpty())
248 return true;
249
250 const auto *ddata = QQmlData::get(instance, false);
251 return !(ddata && ddata->indestructible && ddata->explicitIndestructibleSet);
252 };
253
254 for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
255 auto *instance = it.value().toQObject();
256 if (canDelete(instance, it.key()))
257 QQmlData::markAsDeleted(instance);
258 }
259
260 for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
261 QObject *instance = it.value().toQObject();
262
263 if (canDelete(instance, it.key()))
264 delete instance;
265 }
266
267 QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::clear();
268 }
269
270 using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::value;
271 using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::take;
272 };
273
274 SingletonInstances singletonInstances;
275 QHash<int, QQmlGadgetPtrWrapper *> cachedValueTypeInstances;
276
277 static bool s_designerMode;
278
279 void cleanupScarceResources();
280};
281
282/*
283 This function should be called prior to evaluation of any js expression,
284 so that scarce resources are not freed prematurely (eg, if there is a
285 nested javascript expression).
286 */
287inline void QQmlEnginePrivate::referenceScarceResources()
288{
289 scarceResourcesRefCount += 1;
290}
291
292/*
293 This function should be called after evaluation of the js expression is
294 complete, and so the scarce resources may be freed safely.
295 */
296inline void QQmlEnginePrivate::dereferenceScarceResources()
297{
298 Q_ASSERT(scarceResourcesRefCount > 0);
299 scarceResourcesRefCount -= 1;
300
301 // if the refcount is zero, then evaluation of the "top level"
302 // expression must have completed. We can safely release the
303 // scarce resources.
304 if (Q_LIKELY(scarceResourcesRefCount == 0)) {
305 if (Q_UNLIKELY(!v4Engine->scarceResources.isEmpty())) {
306 cleanupScarceResources();
307 }
308 }
309}
310
311QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
312{
313 Q_ASSERT(e);
314
315 return e->d_func();
316}
317
318const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
319{
320 Q_ASSERT(e);
321
322 return e ? e->d_func() : nullptr;
323}
324
325template<typename Context>
326QQmlEnginePrivate *contextEngine(const Context &context)
327{
328 if (!context)
329 return nullptr;
330 if (QQmlEngine *engine = context->engine())
331 return QQmlEnginePrivate::get(engine);
332 return nullptr;
333}
334
335QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
336{
337 return contextEngine(c);
338}
339
340QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlRefPointer<QQmlContextData> &c)
341{
342 return contextEngine(c);
343}
344
345QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
346{
347 Q_ASSERT(p);
348
349 return p->q_func();
350}
351
352QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
353{
354 QQmlEngine *qmlEngine = e->qmlEngine();
355 if (!qmlEngine)
356 return nullptr;
357 return get(qmlEngine);
358}
359
360template<>
361Q_QML_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
362
363template<typename T>
364T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
365 return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
366}
367
368class QQmlComponentPrivate;
369struct LoadHelper final : QQmlTypeLoader::Blob
370{
371public:
376
378 QQmlTypeLoader *loader, QAnyStringView uri, QAnyStringView typeName,
379 QQmlTypeLoader::Mode mode);
380
381 QQmlType type() const { return m_type; }
382 QQmlTypeLoader::Mode mode() const { return m_mode; }
383 ResolveTypeResult resolveTypeResult() const { return m_resolveTypeResult; }
384
385 void registerCallback(QQmlComponentPrivate *callback);
386 void unregisterCallback(QQmlComponentPrivate *callback);
387
388protected:
389 void done() final;
390 void completed() final;
391 void dataReceived(const SourceCodeData &) final;
392 void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) final { Q_UNREACHABLE(); }
393
394private:
395 bool couldFindModule() const;
396 QString m_uri;
397 QString m_typeName;
398 QQmlType m_type;
399 QQmlComponentPrivate *m_callback = nullptr;
400 QQmlTypeLoader::Mode m_mode = QQmlTypeLoader::Synchronous;
402};
403
404
405QT_END_NAMESPACE
406
407#endif // QQMLENGINE_P_H
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
QQmlApplicationEngine provides a convenient way to load an application from a single QML file.
friend class QQmlEnginePrivate
QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *)
QQmlJavaScriptExpressionGuard * next
static QQmlJavaScriptExpressionGuard * New(QQmlJavaScriptExpression *e, QQmlEngine *engine)
QQmlJavaScriptExpression * expression
static QUrl urlFromFilePath(const QString &filePath)
static QString translationsDirectoryFromLocalUrl(const QUrl &url)
QQmlEnginePrivate * contextEngine(const Context &context)
LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri, QAnyStringView typeName, QQmlTypeLoader::Mode mode)
void dataReceived(const SourceCodeData &) final
Invoked when data for the blob is received.
QQmlType type() const
void completed() final
Invoked on the main thread sometime after done() was called on the load thread.
void registerCallback(QQmlComponentPrivate *callback)
void unregisterCallback(QQmlComponentPrivate *callback)
ResolveTypeResult resolveTypeResult() const
QQmlTypeLoader::Mode mode() const
void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) final
void done() final
Invoked once data has either been received or a network error occurred, and all dependencies are comp...
QQmlJavaScriptExpression * m_expression
static void trigger(QPropertyObserver *, QUntypedPropertyData *)
TriggerList * next
TriggerList(QQmlJavaScriptExpression *expression)