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