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 QQmlValueTypeFactory valueTypes;
205 // Unfortunate workaround to avoid a circular dependency between
206 // qqmlengine_p.h and qqmlincubator_p.h
208 QIntrusiveListNode next;
209 // Unfortunate workaround for MSVC
210 QIntrusiveListNode nextWaitingFor;
212 QIntrusiveList<Incubator, &Incubator::next> incubatorList;
213 unsigned int incubatorCount;
214 QQmlIncubationController *incubationController;
215 void incubate(QQmlIncubator &, QQmlContextData *);
217 // These methods may be called from any thread
218 inline bool isEngineThread() const;
219 inline static bool isEngineThread(const QQmlEngine *);
221 inline void deleteInEngineThread(T *);
223 inline static void deleteInEngineThread(QQmlEngine *, T *);
225 // These methods may be called from the loader thread
226 QQmlMetaType::ModuleApiInstance *moduleApiInstance(const QQmlMetaType::ModuleApi &module);
228 // These methods may be called from the loader thread
229 inline QQmlPropertyCache *cache(QObject *obj);
230 inline QQmlPropertyCache *cache(const QMetaObject *);
231 inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error);
233 // These methods may be called from the loader thread
235 QObject *toQObject(const QVariant &, bool *ok = 0) const;
236 QQmlMetaType::TypeCategory typeCategory(int) const;
237 bool isList(int) const;
238 int listType(int) const;
239 QQmlMetaObject rawMetaObjectForType(int) const;
240 QQmlMetaObject metaObjectForType(int) const;
241 QQmlPropertyCache *propertyCacheForType(int);
242 QQmlPropertyCache *rawPropertyCacheForType(int);
243 void registerCompositeType(QQmlCompiledData *);
244 void unregisterCompositeType(QQmlCompiledData *);
246 bool isTypeLoaded(const QUrl &url) const;
247 bool isScriptLoaded(const QUrl &url) const;
249 inline void setDebugChangesCache(const QHash<QUrl, QByteArray> &changes);
250 inline QHash<QUrl, QByteArray> debugChangesCache();
253 void warning(const QQmlError &);
254 void warning(const QList<QQmlError> &);
255 void warning(QQmlDelayedError *);
256 static void warning(QQmlEngine *, const QQmlError &);
257 static void warning(QQmlEngine *, const QList<QQmlError> &);
258 static void warning(QQmlEngine *, QQmlDelayedError *);
259 static void warning(QQmlEnginePrivate *, const QQmlError &);
260 static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
262 inline static QV8Engine *getV8Engine(QQmlEngine *e);
263 inline static QQmlEnginePrivate *get(QQmlEngine *e);
264 inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
265 inline static QQmlEnginePrivate *get(QQmlContext *c);
266 inline static QQmlEnginePrivate *get(QQmlContextData *c);
267 inline static QQmlEngine *get(QQmlEnginePrivate *p);
269 static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
270 static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor);
271 static void defineQtQuick2Module();
273 static bool qml_debugging_enabled;
275 mutable QMutex mutex;
278 // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.
279 // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
280 // either idle, or is running with the main thread blocked, no locking is necessary. This way
281 // we only pay for locking when we have to.
282 // Consequently, this class should only be used to protect simple accesses or modifications of the
283 // QQmlEnginePrivate structures or operations that can be guarenteed not to start activity
284 // on the loader thread.
285 // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex
286 // QMutex instance and multiple Lockers are recursive in the same thread.
290 inline Locker(const QQmlEngine *);
291 inline Locker(const QQmlEnginePrivate *);
294 inline void unlock();
295 inline void relock();
298 const QQmlEnginePrivate *m_ep;
302 // Must be called locked
303 QQmlPropertyCache *createCache(const QMetaObject *);
304 QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
306 // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
307 // the threaded loader. Only access them through their respective accessor methods.
308 QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *> moduleApiInstances;
309 QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
310 QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
311 QHash<int, int> m_qmlLists;
312 QHash<int, QQmlCompiledData *> m_compositeTypes;
313 QHash<QUrl, QByteArray> debugChangesHash;
315 // These members is protected by the full QQmlEnginePrivate::mutex mutex
316 struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
317 QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
318 void doDeleteInEngineThread();
321 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
322 : m_ep(QQmlEnginePrivate::get(e))
327 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
328 : m_ep(e), m_locked(false)
333 QQmlEnginePrivate::Locker::~Locker()
338 void QQmlEnginePrivate::Locker::unlock()
341 m_ep->mutex.unlock();
346 void QQmlEnginePrivate::Locker::relock()
349 if (m_ep->typeLoader.isConcurrent()) {
356 Returns true if the calling thread is the QQmlEngine thread.
358 bool QQmlEnginePrivate::isEngineThread() const
360 Q_Q(const QQmlEngine);
361 return QThread::currentThread() == q->thread();
365 Returns true if the calling thread is the QQmlEngine \a engine thread.
367 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
370 return QQmlEnginePrivate::get(engine)->isEngineThread();
374 Delete \a value in the engine thread. If the calling thread is the engine
375 thread, \a value will be deleted immediately.
377 This method should be used for *any* type that has resources that need to
378 be freed in the engine thread. This is generally types that use V8 handles.
379 As there is some small overhead in checking the current thread, it is best
380 practice to check if any V8 handles actually need to be freed and delete
381 the instance directly if not.
384 void QQmlEnginePrivate::deleteInEngineThread(T *value)
389 if (isEngineThread()) {
392 struct I : public Deletable {
393 I(T *value) : value(value) {}
394 ~I() { delete value; }
399 bool wasEmpty = toDeleteInEngineThread.isEmpty();
400 toDeleteInEngineThread.append(i);
403 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
408 Delete \a value in the \a engine thread. If the calling thread is the engine
409 thread, \a value will be deleted immediately.
412 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
415 QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
419 Returns a QQmlPropertyCache for \a obj if one is available.
421 If \a obj is null, being deleted or contains a dynamic meta object 0
424 The returned cache is not referenced, so if it is to be stored, call addref().
426 XXX thread There is a potential future race condition in this and all the cache()
427 functions. As the QQmlPropertyCache is returned unreferenced, when called
428 from the loader thread, it is possible that the cache will have been dereferenced
429 and deleted before the loader thread has a chance to use or reference it. This
430 can't currently happen as the cache holds a reference to the
431 QQmlPropertyCache until the QQmlEngine is destroyed.
433 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
435 if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
439 const QMetaObject *mo = obj->metaObject();
440 QQmlPropertyCache *rv = propertyCache.value(mo);
441 if (!rv) rv = createCache(mo);
446 Returns a QQmlPropertyCache for \a metaObject.
448 As the cache is persisted for the life of the engine, \a metaObject must be
449 a static "compile time" meta-object, or a meta-object that is otherwise known to
450 exist for the lifetime of the QQmlEngine.
452 The returned cache is not referenced, so if it is to be stored, call addref().
454 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
456 Q_ASSERT(metaObject);
459 QQmlPropertyCache *rv = propertyCache.value(metaObject);
460 if (!rv) rv = createCache(metaObject);
465 Returns a QQmlPropertyCache for \a type with \a minorVersion.
467 The returned cache is not referenced, so if it is to be stored, call addref().
469 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
473 if (minorVersion == -1 || !type->containsRevisionedAttributes())
474 return cache(type->metaObject());
477 QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
478 if (!rv) rv = createCache(type, minorVersion, error);
482 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
486 return e->d_func()->v8engine();
489 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
496 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
503 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
505 return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0;
508 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
510 return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0;
513 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
520 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
523 propertyCapture->captureProperty(n);
526 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
529 propertyCapture->captureProperty(o, c, n);
532 void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes)
535 foreach (const QUrl &key, changes.keys())
536 debugChangesHash.insert(key, changes.value(key));
539 QHash<QUrl, QByteArray> QQmlEnginePrivate::debugChangesCache()
542 return debugChangesHash;
547 #endif // QQMLENGINE_P_H