1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #ifndef QQMLENGINE_P_H
43 #define QQMLENGINE_P_H
49 // This file is not part of the Qt API. It exists purely as an
50 // implementation detail. This header file may change from version to
51 // version without notice, or even be removed.
56 #include "qqmlengine.h"
58 #include "qqmltypeloader_p.h"
59 #include "qqmlimport_p.h"
60 #include <private/qpodvector_p.h>
62 #include "qqmlvaluetype_p.h"
63 #include "qqmlcontext.h"
64 #include "qqmlcontext_p.h"
65 #include "qqmlexpression.h"
66 #include "qqmlproperty_p.h"
67 #include "qqmlpropertycache_p.h"
68 #include "qqmlmetatype_p.h"
69 #include "qqmldirparser_p.h"
70 #include <private/qintrusivelist_p.h>
71 #include <private/qrecyclepool_p.h>
73 #include <QtCore/qlist.h>
74 #include <QtCore/qpair.h>
75 #include <QtCore/qstack.h>
76 #include <QtCore/qmutex.h>
77 #include <QtCore/qstring.h>
78 #include <QtCore/qthread.h>
80 #include <private/qobject_p.h>
82 #include <private/qv8engine_p.h>
83 #include <private/qjsengine_p.h>
89 class QQmlContextPrivate;
91 class QQmlImportDatabase;
93 class QNetworkAccessManager;
94 class QQmlNetworkAccessManagerFactory;
95 class QQmlAbstractBinding;
96 class QQmlTypeNameCache;
97 class QQmlComponentAttached;
99 class QQmlDelayedError;
100 class QQuickWorkerScriptEngine;
105 // This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
106 // The inline method definitions are in qqmlexpression_p.h
107 class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint
110 inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *);
112 static inline void endpointCallback(QQmlNotifierEndpoint *);
113 static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e,
115 inline void Delete();
117 QQmlJavaScriptExpression *expression;
118 QQmlJavaScriptExpressionGuard *next;
121 class Q_QML_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
123 Q_DECLARE_PUBLIC(QQmlEngine)
125 QQmlEnginePrivate(QQmlEngine *);
126 ~QQmlEnginePrivate();
130 class PropertyCapture {
132 inline virtual ~PropertyCapture() {}
133 virtual void captureProperty(QQmlNotifier *) = 0;
134 virtual void captureProperty(QObject *, int, int) = 0;
137 PropertyCapture *propertyCapture;
138 inline void captureProperty(QQmlNotifier *);
139 inline void captureProperty(QObject *, int, int);
141 QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
143 QQmlContext *rootContext;
146 bool outputWarningsToStdErr;
148 QQmlContextData *sharedContext;
149 QObject *sharedScope;
151 // Registered cleanup handlers
152 QQmlCleanup *cleanup;
154 // Bindings that have had errors during startup
155 QQmlDelayedError *erroredBindings;
156 int inProgressCreations;
158 QV8Engine *v8engine() const { return q_func()->handle(); }
160 QQuickWorkerScriptEngine *getWorkerScriptEngine();
161 QQuickWorkerScriptEngine *workerScriptEngine;
165 typedef QPair<QQmlGuard<QObject>,int> FinalizeCallback;
166 void registerFinalizeCallback(QObject *obj, int index);
170 QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
171 QNetworkAccessManager *getNetworkAccessManager() const;
172 mutable QNetworkAccessManager *networkAccessManager;
173 mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
175 QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
177 // Scarce resources are "exceptionally high cost" QVariant types where allowing the
178 // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
179 // out-of-resource situations. When such a resource is passed into JavaScript we
180 // add it to the scarceResources list and it is destroyed when we return from the
181 // JavaScript execution that created it. The user can prevent this behavior by
182 // calling preserve() on the object which removes it from this scarceResource list.
183 class ScarceResourceData {
185 ScarceResourceData(const QVariant &data) : data(data) {}
187 QIntrusiveListNode node;
189 QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
190 int scarceResourcesRefCount;
191 void referenceScarceResources();
192 void dereferenceScarceResources();
194 QQmlTypeLoader typeLoader;
195 QQmlImportDatabase importDatabase;
197 QString offlineStoragePath;
199 mutable quint32 uniqueId;
200 inline quint32 getUniqueId() const {
204 QQmlValueTypeFactory valueTypes;
206 // Unfortunate workaround to avoid a circular dependency between
207 // qqmlengine_p.h and qqmlincubator_p.h
209 QIntrusiveListNode next;
210 // Unfortunate workaround for MSVC
211 QIntrusiveListNode nextWaitingFor;
213 QIntrusiveList<Incubator, &Incubator::next> incubatorList;
214 unsigned int incubatorCount;
215 QQmlIncubationController *incubationController;
216 void incubate(QQmlIncubator &, QQmlContextData *);
218 // These methods may be called from any thread
219 inline bool isEngineThread() const;
220 inline static bool isEngineThread(const QQmlEngine *);
222 inline void deleteInEngineThread(T *);
224 inline static void deleteInEngineThread(QQmlEngine *, T *);
226 // These methods may be called from the loader thread
227 QQmlMetaType::ModuleApiInstance *moduleApiInstance(const QQmlMetaType::ModuleApi &module);
229 // These methods may be called from the loader thread
230 inline QQmlPropertyCache *cache(QObject *obj);
231 inline QQmlPropertyCache *cache(const QMetaObject *);
232 inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error);
234 // These methods may be called from the loader thread
236 QObject *toQObject(const QVariant &, bool *ok = 0) const;
237 QQmlMetaType::TypeCategory typeCategory(int) const;
238 bool isList(int) const;
239 int listType(int) const;
240 const QMetaObject *rawMetaObjectForType(int) const;
241 const QMetaObject *metaObjectForType(int) const;
242 void registerCompositeType(QQmlCompiledData *);
245 void warning(const QQmlError &);
246 void warning(const QList<QQmlError> &);
247 static void warning(QQmlEngine *, const QQmlError &);
248 static void warning(QQmlEngine *, const QList<QQmlError> &);
249 static void warning(QQmlEnginePrivate *, const QQmlError &);
250 static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
252 inline static QV8Engine *getV8Engine(QQmlEngine *e);
253 inline static QQmlEnginePrivate *get(QQmlEngine *e);
254 inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
255 inline static QQmlEnginePrivate *get(QQmlContext *c);
256 inline static QQmlEnginePrivate *get(QQmlContextData *c);
257 inline static QQmlEngine *get(QQmlEnginePrivate *p);
259 static QString urlToLocalFileOrQrc(const QUrl& url);
260 static QString urlToLocalFileOrQrc(const QString& url);
262 static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
263 static void defineModule();
265 static bool qml_debugging_enabled;
267 mutable QMutex mutex;
270 // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.
271 // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
272 // either idle, or is running with the main thread blocked, no locking is necessary. This way
273 // we only pay for locking when we have to.
274 // Consequently, this class should only be used to protect simple accesses or modifications of the
275 // QQmlEnginePrivate structures or operations that can be guarenteed not to start activity
276 // on the loader thread.
277 // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex
278 // QMutex instance and multiple Lockers are recursive in the same thread.
282 inline Locker(const QQmlEngine *);
283 inline Locker(const QQmlEnginePrivate *);
286 inline void unlock();
287 inline void relock();
290 const QQmlEnginePrivate *m_ep;
294 // Must be called locked
295 QQmlPropertyCache *createCache(const QMetaObject *);
296 QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
298 // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
299 // the threaded loader. Only access them through their respective accessor methods.
300 QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *> moduleApiInstances;
301 QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
302 QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
303 QHash<int, int> m_qmlLists;
304 QHash<int, QQmlCompiledData *> m_compositeTypes;
306 // These members is protected by the full QQmlEnginePrivate::mutex mutex
307 struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
308 QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
309 void doDeleteInEngineThread();
312 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
313 : m_ep(QQmlEnginePrivate::get(e))
318 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
319 : m_ep(e), m_locked(false)
324 QQmlEnginePrivate::Locker::~Locker()
329 void QQmlEnginePrivate::Locker::unlock()
332 m_ep->mutex.unlock();
337 void QQmlEnginePrivate::Locker::relock()
340 if (m_ep->typeLoader.isConcurrent()) {
347 Returns true if the calling thread is the QQmlEngine thread.
349 bool QQmlEnginePrivate::isEngineThread() const
351 Q_Q(const QQmlEngine);
352 return QThread::currentThread() == q->thread();
356 Returns true if the calling thread is the QQmlEngine \a engine thread.
358 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
361 return QQmlEnginePrivate::get(engine)->isEngineThread();
365 Delete \a value in the engine thread. If the calling thread is the engine
366 thread, \a value will be deleted immediately.
368 This method should be used for *any* type that has resources that need to
369 be freed in the engine thread. This is generally types that use V8 handles.
370 As there is some small overhead in checking the current thread, it is best
371 practice to check if any V8 handles actually need to be freed and delete
372 the instance directly if not.
375 void QQmlEnginePrivate::deleteInEngineThread(T *value)
380 if (isEngineThread()) {
383 struct I : public Deletable {
384 I(T *value) : value(value) {}
385 ~I() { delete value; }
390 bool wasEmpty = toDeleteInEngineThread.isEmpty();
391 toDeleteInEngineThread.append(i);
394 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
399 Delete \a value in the \a engine thread. If the calling thread is the engine
400 thread, \a value will be deleted immediately.
403 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
406 QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
410 Returns a QQmlPropertyCache for \a obj if one is available.
412 If \a obj is null, being deleted or contains a dynamic meta object 0
415 The returned cache is not referenced, so if it is to be stored, call addref().
417 XXX thread There is a potential future race condition in this and all the cache()
418 functions. As the QQmlPropertyCache is returned unreferenced, when called
419 from the loader thread, it is possible that the cache will have been dereferenced
420 and deleted before the loader thread has a chance to use or reference it. This
421 can't currently happen as the cache holds a reference to the
422 QQmlPropertyCache until the QQmlEngine is destroyed.
424 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
426 if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
430 const QMetaObject *mo = obj->metaObject();
431 QQmlPropertyCache *rv = propertyCache.value(mo);
432 if (!rv) rv = createCache(mo);
437 Returns a QQmlPropertyCache for \a metaObject.
439 As the cache is persisted for the life of the engine, \a metaObject must be
440 a static "compile time" meta-object, or a meta-object that is otherwise known to
441 exist for the lifetime of the QQmlEngine.
443 The returned cache is not referenced, so if it is to be stored, call addref().
445 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
447 Q_ASSERT(metaObject);
450 QQmlPropertyCache *rv = propertyCache.value(metaObject);
451 if (!rv) rv = createCache(metaObject);
456 Returns a QQmlPropertyCache for \a type with \a minorVersion.
458 The returned cache is not referenced, so if it is to be stored, call addref().
460 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
464 if (minorVersion == -1 || !type->containsRevisionedAttributes())
465 return cache(type->metaObject());
468 QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
469 if (!rv) rv = createCache(type, minorVersion, error);
473 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
475 return e->d_func()->v8engine();
478 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
483 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
488 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
490 return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0;
493 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
495 return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0;
498 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
503 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
506 propertyCapture->captureProperty(n);
509 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
512 propertyCapture->captureProperty(o, c, n);
517 #endif // QQMLENGINE_P_H