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 *, void **);
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 *);
244 inline void setDebugChangesCache(const QHash<QUrl, QByteArray> &changes);
245 inline QHash<QUrl, QByteArray> debugChangesCache();
248 void warning(const QQmlError &);
249 void warning(const QList<QQmlError> &);
250 static void warning(QQmlEngine *, const QQmlError &);
251 static void warning(QQmlEngine *, const QList<QQmlError> &);
252 static void warning(QQmlEnginePrivate *, const QQmlError &);
253 static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
255 inline static QV8Engine *getV8Engine(QQmlEngine *e);
256 inline static QQmlEnginePrivate *get(QQmlEngine *e);
257 inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
258 inline static QQmlEnginePrivate *get(QQmlContext *c);
259 inline static QQmlEnginePrivate *get(QQmlContextData *c);
260 inline static QQmlEngine *get(QQmlEnginePrivate *p);
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;
305 QHash<QUrl, QByteArray> debugChangesHash;
307 // These members is protected by the full QQmlEnginePrivate::mutex mutex
308 struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
309 QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
310 void doDeleteInEngineThread();
313 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
314 : m_ep(QQmlEnginePrivate::get(e))
319 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
320 : m_ep(e), m_locked(false)
325 QQmlEnginePrivate::Locker::~Locker()
330 void QQmlEnginePrivate::Locker::unlock()
333 m_ep->mutex.unlock();
338 void QQmlEnginePrivate::Locker::relock()
341 if (m_ep->typeLoader.isConcurrent()) {
348 Returns true if the calling thread is the QQmlEngine thread.
350 bool QQmlEnginePrivate::isEngineThread() const
352 Q_Q(const QQmlEngine);
353 return QThread::currentThread() == q->thread();
357 Returns true if the calling thread is the QQmlEngine \a engine thread.
359 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
362 return QQmlEnginePrivate::get(engine)->isEngineThread();
366 Delete \a value in the engine thread. If the calling thread is the engine
367 thread, \a value will be deleted immediately.
369 This method should be used for *any* type that has resources that need to
370 be freed in the engine thread. This is generally types that use V8 handles.
371 As there is some small overhead in checking the current thread, it is best
372 practice to check if any V8 handles actually need to be freed and delete
373 the instance directly if not.
376 void QQmlEnginePrivate::deleteInEngineThread(T *value)
381 if (isEngineThread()) {
384 struct I : public Deletable {
385 I(T *value) : value(value) {}
386 ~I() { delete value; }
391 bool wasEmpty = toDeleteInEngineThread.isEmpty();
392 toDeleteInEngineThread.append(i);
395 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
400 Delete \a value in the \a engine thread. If the calling thread is the engine
401 thread, \a value will be deleted immediately.
404 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
407 QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
411 Returns a QQmlPropertyCache for \a obj if one is available.
413 If \a obj is null, being deleted or contains a dynamic meta object 0
416 The returned cache is not referenced, so if it is to be stored, call addref().
418 XXX thread There is a potential future race condition in this and all the cache()
419 functions. As the QQmlPropertyCache is returned unreferenced, when called
420 from the loader thread, it is possible that the cache will have been dereferenced
421 and deleted before the loader thread has a chance to use or reference it. This
422 can't currently happen as the cache holds a reference to the
423 QQmlPropertyCache until the QQmlEngine is destroyed.
425 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
427 if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
431 const QMetaObject *mo = obj->metaObject();
432 QQmlPropertyCache *rv = propertyCache.value(mo);
433 if (!rv) rv = createCache(mo);
438 Returns a QQmlPropertyCache for \a metaObject.
440 As the cache is persisted for the life of the engine, \a metaObject must be
441 a static "compile time" meta-object, or a meta-object that is otherwise known to
442 exist for the lifetime of the QQmlEngine.
444 The returned cache is not referenced, so if it is to be stored, call addref().
446 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
448 Q_ASSERT(metaObject);
451 QQmlPropertyCache *rv = propertyCache.value(metaObject);
452 if (!rv) rv = createCache(metaObject);
457 Returns a QQmlPropertyCache for \a type with \a minorVersion.
459 The returned cache is not referenced, so if it is to be stored, call addref().
461 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
465 if (minorVersion == -1 || !type->containsRevisionedAttributes())
466 return cache(type->metaObject());
469 QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
470 if (!rv) rv = createCache(type, minorVersion, error);
474 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
478 return e->d_func()->v8engine();
481 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
488 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
495 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
497 return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0;
500 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
502 return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0;
505 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
512 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
515 propertyCapture->captureProperty(n);
518 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
521 propertyCapture->captureProperty(o, c, n);
524 void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes)
527 foreach (const QUrl &key, changes.keys())
528 debugChangesHash.insert(key, changes.value(key));
531 QHash<QUrl, QByteArray> QQmlEnginePrivate::debugChangesCache()
534 return debugChangesHash;
539 #endif // QQMLENGINE_P_H