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 inline QQmlPropertyCache *cache(QObject *obj);
225 inline QQmlPropertyCache *cache(const QMetaObject *);
226 inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error);
228 // These methods may be called from the loader thread
230 QObject *toQObject(const QVariant &, bool *ok = 0) const;
231 QQmlMetaType::TypeCategory typeCategory(int) const;
232 bool isList(int) const;
233 int listType(int) const;
234 QQmlMetaObject rawMetaObjectForType(int) const;
235 QQmlMetaObject metaObjectForType(int) const;
236 QQmlPropertyCache *propertyCacheForType(int);
237 QQmlPropertyCache *rawPropertyCacheForType(int);
238 void registerCompositeType(QQmlCompiledData *);
239 void unregisterCompositeType(QQmlCompiledData *);
241 bool isTypeLoaded(const QUrl &url) const;
242 bool isScriptLoaded(const QUrl &url) const;
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 void warning(QQmlDelayedError *);
251 static void warning(QQmlEngine *, const QQmlError &);
252 static void warning(QQmlEngine *, const QList<QQmlError> &);
253 static void warning(QQmlEngine *, QQmlDelayedError *);
254 static void warning(QQmlEnginePrivate *, const QQmlError &);
255 static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
257 inline static QV8Engine *getV8Engine(QQmlEngine *e);
258 inline static QQmlEnginePrivate *get(QQmlEngine *e);
259 inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
260 inline static QQmlEnginePrivate *get(QQmlContext *c);
261 inline static QQmlEnginePrivate *get(QQmlContextData *c);
262 inline static QQmlEngine *get(QQmlEnginePrivate *p);
264 static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
265 static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor);
266 static void defineQtQuick2Module();
268 static bool qml_debugging_enabled;
270 mutable QMutex mutex;
273 // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.
274 // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
275 // either idle, or is running with the main thread blocked, no locking is necessary. This way
276 // we only pay for locking when we have to.
277 // Consequently, this class should only be used to protect simple accesses or modifications of the
278 // QQmlEnginePrivate structures or operations that can be guarenteed not to start activity
279 // on the loader thread.
280 // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex
281 // QMutex instance and multiple Lockers are recursive in the same thread.
285 inline Locker(const QQmlEngine *);
286 inline Locker(const QQmlEnginePrivate *);
289 inline void unlock();
290 inline void relock();
293 const QQmlEnginePrivate *m_ep;
297 // Must be called locked
298 QQmlPropertyCache *createCache(const QMetaObject *);
299 QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
301 // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
302 // the threaded loader. Only access them through their respective accessor methods.
303 QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
304 QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
305 QHash<int, int> m_qmlLists;
306 QHash<int, QQmlCompiledData *> m_compositeTypes;
307 QHash<QUrl, QByteArray> debugChangesHash;
309 // These members is protected by the full QQmlEnginePrivate::mutex mutex
310 struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
311 QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
312 void doDeleteInEngineThread();
315 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
316 : m_ep(QQmlEnginePrivate::get(e))
321 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
322 : m_ep(e), m_locked(false)
327 QQmlEnginePrivate::Locker::~Locker()
332 void QQmlEnginePrivate::Locker::unlock()
335 m_ep->mutex.unlock();
340 void QQmlEnginePrivate::Locker::relock()
343 if (m_ep->typeLoader.isConcurrent()) {
350 Returns true if the calling thread is the QQmlEngine thread.
352 bool QQmlEnginePrivate::isEngineThread() const
354 Q_Q(const QQmlEngine);
355 return QThread::currentThread() == q->thread();
359 Returns true if the calling thread is the QQmlEngine \a engine thread.
361 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
364 return QQmlEnginePrivate::get(engine)->isEngineThread();
368 Delete \a value in the engine thread. If the calling thread is the engine
369 thread, \a value will be deleted immediately.
371 This method should be used for *any* type that has resources that need to
372 be freed in the engine thread. This is generally types that use V8 handles.
373 As there is some small overhead in checking the current thread, it is best
374 practice to check if any V8 handles actually need to be freed and delete
375 the instance directly if not.
378 void QQmlEnginePrivate::deleteInEngineThread(T *value)
383 if (isEngineThread()) {
386 struct I : public Deletable {
387 I(T *value) : value(value) {}
388 ~I() { delete value; }
393 bool wasEmpty = toDeleteInEngineThread.isEmpty();
394 toDeleteInEngineThread.append(i);
397 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
402 Delete \a value in the \a engine thread. If the calling thread is the engine
403 thread, \a value will be deleted immediately.
406 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
409 QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
413 Returns a QQmlPropertyCache for \a obj if one is available.
415 If \a obj is null, being deleted or contains a dynamic meta object 0
418 The returned cache is not referenced, so if it is to be stored, call addref().
420 XXX thread There is a potential future race condition in this and all the cache()
421 functions. As the QQmlPropertyCache is returned unreferenced, when called
422 from the loader thread, it is possible that the cache will have been dereferenced
423 and deleted before the loader thread has a chance to use or reference it. This
424 can't currently happen as the cache holds a reference to the
425 QQmlPropertyCache until the QQmlEngine is destroyed.
427 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
429 if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
433 const QMetaObject *mo = obj->metaObject();
434 QQmlPropertyCache *rv = propertyCache.value(mo);
435 if (!rv) rv = createCache(mo);
440 Returns a QQmlPropertyCache for \a metaObject.
442 As the cache is persisted for the life of the engine, \a metaObject must be
443 a static "compile time" meta-object, or a meta-object that is otherwise known to
444 exist for the lifetime of the QQmlEngine.
446 The returned cache is not referenced, so if it is to be stored, call addref().
448 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
450 Q_ASSERT(metaObject);
453 QQmlPropertyCache *rv = propertyCache.value(metaObject);
454 if (!rv) rv = createCache(metaObject);
459 Returns a QQmlPropertyCache for \a type with \a minorVersion.
461 The returned cache is not referenced, so if it is to be stored, call addref().
463 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
467 if (minorVersion == -1 || !type->containsRevisionedAttributes())
468 return cache(type->metaObject());
471 QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
472 if (!rv) rv = createCache(type, minorVersion, error);
476 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
480 return e->d_func()->v8engine();
483 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
490 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
497 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
499 return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0;
502 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
504 return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0;
507 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
514 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
517 propertyCapture->captureProperty(n);
520 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
523 propertyCapture->captureProperty(o, c, n);
526 void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes)
529 foreach (const QUrl &key, changes.keys())
530 debugChangesHash.insert(key, changes.value(key));
533 QHash<QUrl, QByteArray> QQmlEnginePrivate::debugChangesCache()
536 return debugChangesHash;
541 #endif // QQMLENGINE_P_H