1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #ifndef QDECLARATIVEENGINE_P_H
43 #define QDECLARATIVEENGINE_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 "qdeclarativeengine.h"
58 #include "qdeclarativetypeloader_p.h"
59 #include "qdeclarativeimport_p.h"
60 #include <private/qpodvector_p.h>
61 #include "qdeclarative.h"
62 #include "qdeclarativevaluetype_p.h"
63 #include "qdeclarativecontext.h"
64 #include "qdeclarativecontext_p.h"
65 #include "qdeclarativeexpression.h"
66 #include "qdeclarativeimageprovider.h"
67 #include "qdeclarativeproperty_p.h"
68 #include "qdeclarativepropertycache_p.h"
69 #include "qdeclarativemetatype_p.h"
70 #include "qdeclarativedirparser_p.h"
71 #include <private/qintrusivelist_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>
86 class QDeclarativeContext;
87 class QDeclarativeEngine;
88 class QDeclarativeContextPrivate;
89 class QDeclarativeExpression;
90 class QDeclarativeImportDatabase;
92 class QNetworkAccessManager;
93 class QDeclarativeNetworkAccessManagerFactory;
94 class QDeclarativeAbstractBinding;
95 class QDeclarativeTypeNameCache;
96 class QDeclarativeComponentAttached;
97 class QDeclarativeCleanup;
98 class QDeclarativeDelayedError;
99 class QDeclarativeWorkerScriptEngine;
100 class QDeclarativeVME;
103 class QDeclarativeIncubator;
106 class Q_DECLARATIVE_EXPORT QDeclarativeEnginePrivate : public QObjectPrivate
108 Q_DECLARE_PUBLIC(QDeclarativeEngine)
110 QDeclarativeEnginePrivate(QDeclarativeEngine *);
111 ~QDeclarativeEnginePrivate();
115 struct CapturedProperty {
116 CapturedProperty(QObject *o, int c, int n)
117 : object(o), coreIndex(c), notifier(0), notifyIndex(n) {}
118 CapturedProperty(QDeclarativeNotifier *n)
119 : object(0), coreIndex(-1), notifier(n), notifyIndex(-1) {}
123 QDeclarativeNotifier *notifier;
126 bool captureProperties;
127 QPODVector<CapturedProperty> capturedProperties;
129 QDeclarativeContext *rootContext;
132 bool outputWarningsToStdErr;
134 QDeclarativeContextData *sharedContext;
135 QObject *sharedScope;
137 // Registered cleanup handlers
138 QDeclarativeCleanup *cleanup;
140 // Bindings that have had errors during startup
141 QDeclarativeDelayedError *erroredBindings;
142 int inProgressCreations;
144 QV8Engine *v8engine() const { return q_func()->handle(); }
146 QDeclarativeWorkerScriptEngine *getWorkerScriptEngine();
147 QDeclarativeWorkerScriptEngine *workerScriptEngine;
151 typedef QPair<QDeclarativeGuard<QObject>,int> FinalizeCallback;
152 void registerFinalizeCallback(QObject *obj, int index);
154 QDeclarativeVME *activeVME;
156 QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
157 QNetworkAccessManager *getNetworkAccessManager() const;
158 mutable QNetworkAccessManager *networkAccessManager;
159 mutable QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory;
161 QHash<QString,QSharedPointer<QDeclarativeImageProvider> > imageProviders;
162 QDeclarativeImageProvider::ImageType getImageProviderType(const QUrl &url);
163 QSGTexture *getTextureFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
164 QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
165 QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
167 // Scarce resources are "exceptionally high cost" QVariant types where allowing the
168 // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
169 // out-of-resource situations. When such a resource is passed into JavaScript we
170 // add it to the scarceResources list and it is destroyed when we return from the
171 // JavaScript execution that created it. The user can prevent this behavior by
172 // calling preserve() on the object which removes it from this scarceResource list.
173 class ScarceResourceData {
175 ScarceResourceData(const QVariant &data) : data(data) {}
177 QIntrusiveListNode node;
179 QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
180 int scarceResourcesRefCount;
181 void referenceScarceResources();
182 void dereferenceScarceResources();
184 QDeclarativeTypeLoader typeLoader;
185 QDeclarativeImportDatabase importDatabase;
187 QString offlineStoragePath;
189 mutable quint32 uniqueId;
190 inline quint32 getUniqueId() const {
194 QDeclarativeValueTypeFactory valueTypes;
196 // Unfortunate workaround to avoid a circular dependency between
197 // qdeclarativeengine_p.h and qdeclarativeincubator_p.h
199 QIntrusiveListNode next;
200 // Unfortunate workaround for MSVC
201 QIntrusiveListNode nextWaitingFor;
203 QIntrusiveList<Incubator, &Incubator::next> incubatorList;
204 unsigned int incubatorCount;
205 QDeclarativeIncubationController *incubationController;
206 void incubate(QDeclarativeIncubator &, QDeclarativeContextData *);
208 // These methods may be called from any thread
209 inline bool isEngineThread() const;
210 inline static bool isEngineThread(const QDeclarativeEngine *);
212 inline void deleteInEngineThread(T *);
214 inline static void deleteInEngineThread(QDeclarativeEngine *, T *);
216 // These methods may be called from the loader thread
217 QDeclarativeMetaType::ModuleApiInstance *moduleApiInstance(const QDeclarativeMetaType::ModuleApi &module);
219 // These methods may be called from the loader thread
220 inline QDeclarativePropertyCache *cache(QObject *obj);
221 inline QDeclarativePropertyCache *cache(const QMetaObject *);
222 inline QDeclarativePropertyCache *cache(QDeclarativeType *, int, QDeclarativeError &error);
224 // These methods may be called from the loader thread
226 QObject *toQObject(const QVariant &, bool *ok = 0) const;
227 QDeclarativeMetaType::TypeCategory typeCategory(int) const;
228 bool isList(int) const;
229 int listType(int) const;
230 const QMetaObject *rawMetaObjectForType(int) const;
231 const QMetaObject *metaObjectForType(int) const;
232 void registerCompositeType(QDeclarativeCompiledData *);
235 void warning(const QDeclarativeError &);
236 void warning(const QList<QDeclarativeError> &);
237 static void warning(QDeclarativeEngine *, const QDeclarativeError &);
238 static void warning(QDeclarativeEngine *, const QList<QDeclarativeError> &);
239 static void warning(QDeclarativeEnginePrivate *, const QDeclarativeError &);
240 static void warning(QDeclarativeEnginePrivate *, const QList<QDeclarativeError> &);
242 inline static QV8Engine *getV8Engine(QDeclarativeEngine *e);
243 inline static QDeclarativeEnginePrivate *get(QDeclarativeEngine *e);
244 inline static const QDeclarativeEnginePrivate *get(const QDeclarativeEngine *e);
245 inline static QDeclarativeEnginePrivate *get(QDeclarativeContext *c);
246 inline static QDeclarativeEnginePrivate *get(QDeclarativeContextData *c);
247 inline static QDeclarativeEngine *get(QDeclarativeEnginePrivate *p);
249 static QString urlToLocalFileOrQrc(const QUrl& url);
250 static QString urlToLocalFileOrQrc(const QString& url);
252 static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
253 static void defineModule();
255 static bool qml_debugging_enabled;
257 QSGContext *sgContext;
259 mutable QMutex mutex;
262 // Locker locks the QDeclarativeEnginePrivate data structures for read and write, if necessary.
263 // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
264 // either idle, or is running with the main thread blocked, no locking is necessary. This way
265 // we only pay for locking when we have to.
266 // Consequently, this class should only be used to protect simple accesses or modifications of the
267 // QDeclarativeEnginePrivate structures or operations that can be guarenteed not to start activity
268 // on the loader thread.
269 // The Locker API is identical to QMutexLocker. Locker reuses the QDeclarativeEnginePrivate::mutex
270 // QMutex instance and multiple Lockers are recursive in the same thread.
274 inline Locker(const QDeclarativeEngine *);
275 inline Locker(const QDeclarativeEnginePrivate *);
278 inline void unlock();
279 inline void relock();
282 const QDeclarativeEnginePrivate *m_ep;
286 // Must be called locked
287 QDeclarativePropertyCache *createCache(const QMetaObject *);
288 QDeclarativePropertyCache *createCache(QDeclarativeType *, int, QDeclarativeError &error);
290 // These members must be protected by a QDeclarativeEnginePrivate::Locker as they are required by
291 // the threaded loader. Only access them through their respective accessor methods.
292 QHash<QDeclarativeMetaType::ModuleApi, QDeclarativeMetaType::ModuleApiInstance *> moduleApiInstances;
293 QHash<const QMetaObject *, QDeclarativePropertyCache *> propertyCache;
294 QHash<QPair<QDeclarativeType *, int>, QDeclarativePropertyCache *> typePropertyCache;
295 QHash<int, int> m_qmlLists;
296 QHash<int, QDeclarativeCompiledData *> m_compositeTypes;
298 // These members is protected by the full QDeclarativeEnginePrivate::mutex mutex
299 struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
300 QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
301 void doDeleteInEngineThread();
304 QDeclarativeEnginePrivate::Locker::Locker(const QDeclarativeEngine *e)
305 : m_ep(QDeclarativeEnginePrivate::get(e))
310 QDeclarativeEnginePrivate::Locker::Locker(const QDeclarativeEnginePrivate *e)
311 : m_ep(e), m_locked(false)
316 QDeclarativeEnginePrivate::Locker::~Locker()
321 void QDeclarativeEnginePrivate::Locker::unlock()
324 m_ep->mutex.unlock();
329 void QDeclarativeEnginePrivate::Locker::relock()
332 if (m_ep->typeLoader.isConcurrent()) {
339 Returns true if the calling thread is the QDeclarativeEngine thread.
341 bool QDeclarativeEnginePrivate::isEngineThread() const
343 Q_Q(const QDeclarativeEngine);
344 return QThread::currentThread() == q->thread();
348 Returns true if the calling thread is the QDeclarativeEngine \a engine thread.
350 bool QDeclarativeEnginePrivate::isEngineThread(const QDeclarativeEngine *engine)
353 return QDeclarativeEnginePrivate::get(engine)->isEngineThread();
357 Delete \a value in the engine thread. If the calling thread is the engine
358 thread, \a value will be deleted immediately.
360 This method should be used for *any* type that has resources that need to
361 be freed in the engine thread. This is generally types that use V8 handles.
362 As there is some small overhead in checking the current thread, it is best
363 practice to check if any V8 handles actually need to be freed and delete
364 the instance directly if not.
367 void QDeclarativeEnginePrivate::deleteInEngineThread(T *value)
369 Q_Q(QDeclarativeEngine);
372 if (isEngineThread()) {
375 struct I : public Deletable {
376 I(T *value) : value(value) {}
377 ~I() { delete value; }
382 bool wasEmpty = toDeleteInEngineThread.isEmpty();
383 toDeleteInEngineThread.append(i);
386 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
391 Delete \a value in the \a engine thread. If the calling thread is the engine
392 thread, \a value will be deleted immediately.
395 void QDeclarativeEnginePrivate::deleteInEngineThread(QDeclarativeEngine *engine, T *value)
398 QDeclarativeEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
402 Returns a QDeclarativePropertyCache for \a obj if one is available.
404 If \a obj is null, being deleted or contains a dynamic meta object 0
407 The returned cache is not referenced, so if it is to be stored, call addref().
409 XXX thread There is a potential future race condition in this and all the cache()
410 functions. As the QDeclarativePropertyCache is returned unreferenced, when called
411 from the loader thread, it is possible that the cache will have been dereferenced
412 and deleted before the loader thread has a chance to use or reference it. This
413 can't currently happen as the cache holds a reference to the
414 QDeclarativePropertyCache until the QDeclarativeEngine is destroyed.
416 QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QObject *obj)
418 if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
422 const QMetaObject *mo = obj->metaObject();
423 QDeclarativePropertyCache *rv = propertyCache.value(mo);
424 if (!rv) rv = createCache(mo);
429 Returns a QDeclarativePropertyCache for \a metaObject.
431 As the cache is persisted for the life of the engine, \a metaObject must be
432 a static "compile time" meta-object, or a meta-object that is otherwise known to
433 exist for the lifetime of the QDeclarativeEngine.
435 The returned cache is not referenced, so if it is to be stored, call addref().
437 QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(const QMetaObject *metaObject)
439 Q_ASSERT(metaObject);
442 QDeclarativePropertyCache *rv = propertyCache.value(metaObject);
443 if (!rv) rv = createCache(metaObject);
448 Returns a QDeclarativePropertyCache for \a type with \a minorVersion.
450 The returned cache is not referenced, so if it is to be stored, call addref().
452 QDeclarativePropertyCache *QDeclarativeEnginePrivate::cache(QDeclarativeType *type, int minorVersion, QDeclarativeError &error)
456 if (minorVersion == -1 || !type->containsRevisionedAttributes())
457 return cache(type->metaObject());
460 QDeclarativePropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
461 if (!rv) rv = createCache(type, minorVersion, error);
465 QV8Engine *QDeclarativeEnginePrivate::getV8Engine(QDeclarativeEngine *e)
467 return e->d_func()->v8engine();
470 QDeclarativeEnginePrivate *QDeclarativeEnginePrivate::get(QDeclarativeEngine *e)
475 const QDeclarativeEnginePrivate *QDeclarativeEnginePrivate::get(const QDeclarativeEngine *e)
480 QDeclarativeEnginePrivate *QDeclarativeEnginePrivate::get(QDeclarativeContext *c)
482 return (c && c->engine()) ? QDeclarativeEnginePrivate::get(c->engine()) : 0;
485 QDeclarativeEnginePrivate *QDeclarativeEnginePrivate::get(QDeclarativeContextData *c)
487 return (c && c->engine) ? QDeclarativeEnginePrivate::get(c->engine) : 0;
490 QDeclarativeEngine *QDeclarativeEnginePrivate::get(QDeclarativeEnginePrivate *p)
497 #endif // QDECLARATIVEENGINE_P_H