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 qqmljavascriptexpression_p.h
107 class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint
110 inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *);
112 static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e,
114 inline void Delete();
116 QQmlJavaScriptExpression *expression;
117 QQmlJavaScriptExpressionGuard *next;
120 class Q_QML_PRIVATE_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
122 Q_DECLARE_PUBLIC(QQmlEngine)
124 QQmlEnginePrivate(QQmlEngine *);
125 ~QQmlEnginePrivate();
129 class PropertyCapture {
131 inline virtual ~PropertyCapture() {}
132 virtual void captureProperty(QQmlNotifier *) = 0;
133 virtual void captureProperty(QObject *, int, int) = 0;
136 PropertyCapture *propertyCapture;
137 inline void captureProperty(QQmlNotifier *);
138 inline void captureProperty(QObject *, int, int);
140 QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
142 QQmlContext *rootContext;
145 bool outputWarningsToStdErr;
147 QQmlContextData *sharedContext;
148 QObject *sharedScope;
150 // Registered cleanup handlers
151 QQmlCleanup *cleanup;
153 // Bindings that have had errors during startup
154 QQmlDelayedError *erroredBindings;
155 int inProgressCreations;
157 QV8Engine *v8engine() const { return q_func()->handle(); }
159 QQuickWorkerScriptEngine *getWorkerScriptEngine();
160 QQuickWorkerScriptEngine *workerScriptEngine;
164 typedef QPair<QQmlGuard<QObject>,int> FinalizeCallback;
165 void registerFinalizeCallback(QObject *obj, int index);
169 QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
170 QNetworkAccessManager *getNetworkAccessManager() const;
171 mutable QNetworkAccessManager *networkAccessManager;
172 mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
174 QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
176 // Scarce resources are "exceptionally high cost" QVariant types where allowing the
177 // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
178 // out-of-resource situations. When such a resource is passed into JavaScript we
179 // add it to the scarceResources list and it is destroyed when we return from the
180 // JavaScript execution that created it. The user can prevent this behavior by
181 // calling preserve() on the object which removes it from this scarceResource list.
182 class ScarceResourceData {
184 ScarceResourceData(const QVariant &data) : data(data) {}
186 QIntrusiveListNode node;
188 QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
189 int scarceResourcesRefCount;
190 void referenceScarceResources();
191 void dereferenceScarceResources();
193 QQmlTypeLoader typeLoader;
194 QQmlImportDatabase importDatabase;
196 QString offlineStoragePath;
198 mutable quint32 uniqueId;
199 inline quint32 getUniqueId() const {
203 // Unfortunate workaround to avoid a circular dependency between
204 // qqmlengine_p.h and qqmlincubator_p.h
206 QIntrusiveListNode next;
207 // Unfortunate workaround for MSVC
208 QIntrusiveListNode nextWaitingFor;
210 QIntrusiveList<Incubator, &Incubator::next> incubatorList;
211 unsigned int incubatorCount;
212 QQmlIncubationController *incubationController;
213 void incubate(QQmlIncubator &, QQmlContextData *);
215 // These methods may be called from any thread
216 inline bool isEngineThread() const;
217 inline static bool isEngineThread(const QQmlEngine *);
219 inline void deleteInEngineThread(T *);
221 inline static void deleteInEngineThread(QQmlEngine *, T *);
223 // These methods may be called from the loader thread
224 QQmlMetaType::SingletonInstance *singletonTypeInstance(const QQmlMetaType::SingletonType &module);
226 // These methods may be called from the loader thread
227 inline QQmlPropertyCache *cache(QObject *obj);
228 inline QQmlPropertyCache *cache(const QMetaObject *);
229 inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error);
231 // These methods may be called from the loader thread
233 QObject *toQObject(const QVariant &, bool *ok = 0) const;
234 QQmlMetaType::TypeCategory typeCategory(int) const;
235 bool isList(int) const;
236 int listType(int) const;
237 QQmlMetaObject rawMetaObjectForType(int) const;
238 QQmlMetaObject metaObjectForType(int) const;
239 QQmlPropertyCache *propertyCacheForType(int);
240 QQmlPropertyCache *rawPropertyCacheForType(int);
241 void registerCompositeType(QQmlCompiledData *);
242 void unregisterCompositeType(QQmlCompiledData *);
244 bool isTypeLoaded(const QUrl &url) const;
245 bool isScriptLoaded(const QUrl &url) const;
247 inline void setDebugChangesCache(const QHash<QUrl, QByteArray> &changes);
248 inline QHash<QUrl, QByteArray> debugChangesCache();
251 void warning(const QQmlError &);
252 void warning(const QList<QQmlError> &);
253 void warning(QQmlDelayedError *);
254 static void warning(QQmlEngine *, const QQmlError &);
255 static void warning(QQmlEngine *, const QList<QQmlError> &);
256 static void warning(QQmlEngine *, QQmlDelayedError *);
257 static void warning(QQmlEnginePrivate *, const QQmlError &);
258 static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
260 inline static QV8Engine *getV8Engine(QQmlEngine *e);
261 inline static QQmlEnginePrivate *get(QQmlEngine *e);
262 inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
263 inline static QQmlEnginePrivate *get(QQmlContext *c);
264 inline static QQmlEnginePrivate *get(QQmlContextData *c);
265 inline static QQmlEngine *get(QQmlEnginePrivate *p);
267 static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
268 static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor);
269 static void defineQtQuick2Module();
271 static bool qml_debugging_enabled;
273 mutable QMutex mutex;
276 // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.
277 // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
278 // either idle, or is running with the main thread blocked, no locking is necessary. This way
279 // we only pay for locking when we have to.
280 // Consequently, this class should only be used to protect simple accesses or modifications of the
281 // QQmlEnginePrivate structures or operations that can be guarenteed not to start activity
282 // on the loader thread.
283 // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex
284 // QMutex instance and multiple Lockers are recursive in the same thread.
288 inline Locker(const QQmlEngine *);
289 inline Locker(const QQmlEnginePrivate *);
292 inline void unlock();
293 inline void relock();
296 const QQmlEnginePrivate *m_ep;
300 // Must be called locked
301 QQmlPropertyCache *createCache(const QMetaObject *);
302 QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
304 // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
305 // the threaded loader. Only access them through their respective accessor methods.
306 QHash<QQmlMetaType::SingletonType, QQmlMetaType::SingletonInstance *> singletonTypeInstances;
307 QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
308 QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
309 QHash<int, int> m_qmlLists;
310 QHash<int, QQmlCompiledData *> m_compositeTypes;
311 QHash<QUrl, QByteArray> debugChangesHash;
313 // These members is protected by the full QQmlEnginePrivate::mutex mutex
314 struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
315 QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
316 void doDeleteInEngineThread();
319 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
320 : m_ep(QQmlEnginePrivate::get(e))
325 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
326 : m_ep(e), m_locked(false)
331 QQmlEnginePrivate::Locker::~Locker()
336 void QQmlEnginePrivate::Locker::unlock()
339 m_ep->mutex.unlock();
344 void QQmlEnginePrivate::Locker::relock()
347 if (m_ep->typeLoader.isConcurrent()) {
354 Returns true if the calling thread is the QQmlEngine thread.
356 bool QQmlEnginePrivate::isEngineThread() const
358 Q_Q(const QQmlEngine);
359 return QThread::currentThread() == q->thread();
363 Returns true if the calling thread is the QQmlEngine \a engine thread.
365 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
368 return QQmlEnginePrivate::get(engine)->isEngineThread();
372 Delete \a value in the engine thread. If the calling thread is the engine
373 thread, \a value will be deleted immediately.
375 This method should be used for *any* type that has resources that need to
376 be freed in the engine thread. This is generally types that use V8 handles.
377 As there is some small overhead in checking the current thread, it is best
378 practice to check if any V8 handles actually need to be freed and delete
379 the instance directly if not.
382 void QQmlEnginePrivate::deleteInEngineThread(T *value)
387 if (isEngineThread()) {
390 struct I : public Deletable {
391 I(T *value) : value(value) {}
392 ~I() { delete value; }
397 bool wasEmpty = toDeleteInEngineThread.isEmpty();
398 toDeleteInEngineThread.append(i);
401 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
406 Delete \a value in the \a engine thread. If the calling thread is the engine
407 thread, \a value will be deleted immediately.
410 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
413 QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
417 Returns a QQmlPropertyCache for \a obj if one is available.
419 If \a obj is null, being deleted or contains a dynamic meta object 0
422 The returned cache is not referenced, so if it is to be stored, call addref().
424 XXX thread There is a potential future race condition in this and all the cache()
425 functions. As the QQmlPropertyCache is returned unreferenced, when called
426 from the loader thread, it is possible that the cache will have been dereferenced
427 and deleted before the loader thread has a chance to use or reference it. This
428 can't currently happen as the cache holds a reference to the
429 QQmlPropertyCache until the QQmlEngine is destroyed.
431 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
433 if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
437 const QMetaObject *mo = obj->metaObject();
438 QQmlPropertyCache *rv = propertyCache.value(mo);
439 if (!rv) rv = createCache(mo);
444 Returns a QQmlPropertyCache for \a metaObject.
446 As the cache is persisted for the life of the engine, \a metaObject must be
447 a static "compile time" meta-object, or a meta-object that is otherwise known to
448 exist for the lifetime of the QQmlEngine.
450 The returned cache is not referenced, so if it is to be stored, call addref().
452 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
454 Q_ASSERT(metaObject);
457 QQmlPropertyCache *rv = propertyCache.value(metaObject);
458 if (!rv) rv = createCache(metaObject);
463 Returns a QQmlPropertyCache for \a type with \a minorVersion.
465 The returned cache is not referenced, so if it is to be stored, call addref().
467 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
471 if (minorVersion == -1 || !type->containsRevisionedAttributes())
472 return cache(type->metaObject());
475 QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
476 if (!rv) rv = createCache(type, minorVersion, error);
480 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
484 return e->d_func()->v8engine();
487 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
494 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
501 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
503 return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0;
506 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
508 return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0;
511 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
518 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
521 propertyCapture->captureProperty(n);
524 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
527 propertyCapture->captureProperty(o, c, n);
530 void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes)
533 foreach (const QUrl &key, changes.keys())
534 debugChangesHash.insert(key, changes.value(key));
537 QHash<QUrl, QByteArray> QQmlEnginePrivate::debugChangesCache()
540 return debugChangesHash;
545 #endif // QQMLENGINE_P_H