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;
115
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 QQmlRefPointer<QQmlContextData>
213 createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
214 const QQmlRefPointer<QQmlContextData> &parentContext,
215 int subComponentIndex, bool isComponentRoot);
216 static void setInternalContext(QObject *This, const QQmlRefPointer<QQmlContextData> &context,
217 QQmlContextData::QmlObjectKind kind)
218 {
219 Q_ASSERT(This);
220 QQmlData *ddata = QQmlData::get(This, /*create*/ true);
221 // NB: copied from QQmlObjectCreator::createInstance()
222 //
223 // the if-statement logic to determine the kind is:
224 // if (static_cast<quint32>(index) == 0 || ddata->rootObjectInCreation || isInlineComponent)
225 // then QQmlContextData::DocumentRoot. here, we pass this through qmltc
226 context->installContext(ddata, kind);
227 Q_ASSERT(qmlEngine(This));
228 }
229
230private:
231 class SingletonInstances : private QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>
232 {
233 public:
234 void convertAndInsert(
235 QV4::ExecutionEngine *engine, const QQmlType::SingletonInstanceInfo::ConstPtr &type,
236 QJSValue *value)
237 {
238 QJSValuePrivate::manageStringOnV4Heap(engine, value);
239 insert(type, *value);
240 }
241
242 void clear()
243 {
244 const auto canDelete = [](QObject *instance, const auto &siinfo) -> bool {
245 if (!instance)
246 return false;
247
248 if (!siinfo->url.isEmpty())
249 return true;
250
251 const auto *ddata = QQmlData::get(instance, false);
252 return !(ddata && ddata->indestructible && ddata->explicitIndestructibleSet);
253 };
254
255 for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
256 auto *instance = it.value().toQObject();
257 if (canDelete(instance, it.key()))
258 QQmlData::markAsDeleted(instance);
259 }
260
261 for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
262 QObject *instance = it.value().toQObject();
263
264 if (canDelete(instance, it.key()))
265 delete instance;
266 }
267
268 QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::clear();
269 }
270
271 using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::value;
272 using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::take;
273 };
274
275 SingletonInstances singletonInstances;
276 QHash<int, QQmlGadgetPtrWrapper *> cachedValueTypeInstances;
277
278 static bool s_designerMode;
279
280 void cleanupScarceResources();
281};
282
283/*
284 This function should be called prior to evaluation of any js expression,
285 so that scarce resources are not freed prematurely (eg, if there is a
286 nested javascript expression).
287 */
288inline void QQmlEnginePrivate::referenceScarceResources()
289{
290 scarceResourcesRefCount += 1;
291}
292
293/*
294 This function should be called after evaluation of the js expression is
295 complete, and so the scarce resources may be freed safely.
296 */
297inline void QQmlEnginePrivate::dereferenceScarceResources()
298{
299 Q_ASSERT(scarceResourcesRefCount > 0);
300 scarceResourcesRefCount -= 1;
301
302 // if the refcount is zero, then evaluation of the "top level"
303 // expression must have completed. We can safely release the
304 // scarce resources.
305 if (Q_LIKELY(scarceResourcesRefCount == 0)) {
306 if (Q_UNLIKELY(!v4Engine->scarceResources.isEmpty())) {
307 cleanupScarceResources();
308 }
309 }
310}
311
312QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
313{
314 Q_ASSERT(e);
315
316 return e->d_func();
317}
318
319const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
320{
321 Q_ASSERT(e);
322
323 return e ? e->d_func() : nullptr;
324}
325
326template<typename Context>
327QQmlEnginePrivate *contextEngine(const Context &context)
328{
329 if (!context)
330 return nullptr;
331 if (QQmlEngine *engine = context->engine())
332 return QQmlEnginePrivate::get(engine);
333 return nullptr;
334}
335
336QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
337{
338 return contextEngine(c);
339}
340
341QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlRefPointer<QQmlContextData> &c)
342{
343 return contextEngine(c);
344}
345
346QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
347{
348 Q_ASSERT(p);
349
350 return p->q_func();
351}
352
353QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
354{
355 QQmlEngine *qmlEngine = e->qmlEngine();
356 if (!qmlEngine)
357 return nullptr;
358 return get(qmlEngine);
359}
360
361template<>
362Q_QML_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
363
364template<typename T>
365T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
366 return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
367}
368
369class QQmlComponentPrivate;
370struct LoadHelper final : QQmlTypeLoader::Blob
371{
372public:
377
379 QQmlTypeLoader *loader, QAnyStringView uri, QAnyStringView typeName,
380 QQmlTypeLoader::Mode mode);
381
382 QQmlType type() const { return m_type; }
383 QQmlTypeLoader::Mode mode() const { return m_mode; }
384 ResolveTypeResult resolveTypeResult() const { return m_resolveTypeResult; }
385
386 void registerCallback(QQmlComponentPrivate *callback);
387 void unregisterCallback(QQmlComponentPrivate *callback);
388
389protected:
390 void done() final;
391 void completed() final;
392 void dataReceived(const SourceCodeData &) final;
393 void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) final { Q_UNREACHABLE(); }
394
395private:
396 bool couldFindModule() const;
397 QString m_uri;
398 QString m_typeName;
399 QQmlType m_type;
400 QQmlComponentPrivate *m_callback = nullptr;
401 QQmlTypeLoader::Mode m_mode = QQmlTypeLoader::Synchronous;
403};
404
405
406QT_END_NAMESPACE
407
408#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)