Initial bundle support
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlengine_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QQMLENGINE_P_H
43 #define QQMLENGINE_P_H
44
45 //
46 //  W A R N I N G
47 //  -------------
48 //
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.
52 //
53 // We mean it.
54 //
55
56 #include "qqmlengine.h"
57
58 #include "qqmltypeloader_p.h"
59 #include "qqmlimport_p.h"
60 #include <private/qpodvector_p.h>
61 #include "qqml.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>
72
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>
79
80 #include <private/qobject_p.h>
81
82 #include <private/qv8engine_p.h>
83 #include <private/qjsengine_p.h>
84
85 QT_BEGIN_NAMESPACE
86
87 class QQmlContext;
88 class QQmlEngine;
89 class QQmlContextPrivate;
90 class QQmlExpression;
91 class QQmlImportDatabase;
92 class QNetworkReply;
93 class QNetworkAccessManager;
94 class QQmlNetworkAccessManagerFactory;
95 class QQmlAbstractBinding;
96 class QQmlTypeNameCache;
97 class QQmlComponentAttached;
98 class QQmlCleanup;
99 class QQmlDelayedError;
100 class QQuickWorkerScriptEngine;
101 class QQmlVME;
102 class QDir;
103 class QQmlIncubator;
104
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
108 {
109 public:
110     inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *);
111
112     static inline void endpointCallback(QQmlNotifierEndpoint *, void **);
113     static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e,
114                                                              QQmlEngine *engine);
115     inline void Delete();
116
117     QQmlJavaScriptExpression *expression;
118     QQmlJavaScriptExpressionGuard *next;
119 };
120
121 class Q_QML_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
122 {
123     Q_DECLARE_PUBLIC(QQmlEngine)
124 public:
125     QQmlEnginePrivate(QQmlEngine *);
126     ~QQmlEnginePrivate();
127
128     void init();
129
130     class PropertyCapture {
131     public:
132         inline virtual ~PropertyCapture() {}
133         virtual void captureProperty(QQmlNotifier *) = 0;
134         virtual void captureProperty(QObject *, int, int) = 0;
135     };
136
137     PropertyCapture *propertyCapture;
138     inline void captureProperty(QQmlNotifier *);
139     inline void captureProperty(QObject *, int, int);
140
141     QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
142
143     QQmlContext *rootContext;
144     bool isDebugging;
145
146     bool outputWarningsToStdErr;
147
148     QQmlContextData *sharedContext;
149     QObject *sharedScope;
150
151     // Registered cleanup handlers
152     QQmlCleanup *cleanup;
153
154     // Bindings that have had errors during startup
155     QQmlDelayedError *erroredBindings;
156     int inProgressCreations;
157
158     QV8Engine *v8engine() const { return q_func()->handle(); }
159
160     QQuickWorkerScriptEngine *getWorkerScriptEngine();
161     QQuickWorkerScriptEngine *workerScriptEngine;
162
163     QUrl baseUrl;
164
165     typedef QPair<QQmlGuard<QObject>,int> FinalizeCallback;
166     void registerFinalizeCallback(QObject *obj, int index);
167
168     QQmlVME *activeVME;
169
170     QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
171     QNetworkAccessManager *getNetworkAccessManager() const;
172     mutable QNetworkAccessManager *networkAccessManager;
173     mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
174
175     QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
176
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 {
184     public:
185         ScarceResourceData(const QVariant &data) : data(data) {}
186         QVariant data;
187         QIntrusiveListNode node;
188     };
189     QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
190     int scarceResourcesRefCount;
191     void referenceScarceResources();
192     void dereferenceScarceResources();
193
194     QQmlTypeLoader typeLoader;
195     QQmlImportDatabase importDatabase;
196
197     QString offlineStoragePath;
198
199     mutable quint32 uniqueId;
200     inline quint32 getUniqueId() const {
201         return uniqueId++;
202     }
203
204     QQmlValueTypeFactory valueTypes;
205
206     // Unfortunate workaround to avoid a circular dependency between 
207     // qqmlengine_p.h and qqmlincubator_p.h
208     struct Incubator {
209         QIntrusiveListNode next;
210         // Unfortunate workaround for MSVC
211         QIntrusiveListNode nextWaitingFor;
212     };
213     QIntrusiveList<Incubator, &Incubator::next> incubatorList;
214     unsigned int incubatorCount;
215     QQmlIncubationController *incubationController;
216     void incubate(QQmlIncubator &, QQmlContextData *);
217
218     // These methods may be called from any thread
219     inline bool isEngineThread() const;
220     inline static bool isEngineThread(const QQmlEngine *);
221     template<typename T>
222     inline void deleteInEngineThread(T *);
223     template<typename T>
224     inline static void deleteInEngineThread(QQmlEngine *, T *);
225
226     // These methods may be called from the loader thread
227     QQmlMetaType::ModuleApiInstance *moduleApiInstance(const QQmlMetaType::ModuleApi &module);
228
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);
233
234     // These methods may be called from the loader thread
235     bool isQObject(int);
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 *);
243
244     void sendQuit();
245     void warning(const QQmlError &);
246     void warning(const QList<QQmlError> &);
247     static void warning(QQmlEngine *, const QQmlError &);
248     static void warning(QQmlEngine *, const QList<QQmlError> &);
249     static void warning(QQmlEnginePrivate *, const QQmlError &);
250     static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
251
252     inline static QV8Engine *getV8Engine(QQmlEngine *e);
253     inline static QQmlEnginePrivate *get(QQmlEngine *e);
254     inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
255     inline static QQmlEnginePrivate *get(QQmlContext *c);
256     inline static QQmlEnginePrivate *get(QQmlContextData *c);
257     inline static QQmlEngine *get(QQmlEnginePrivate *p);
258
259     static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
260     static void defineModule();
261
262     static bool qml_debugging_enabled;
263
264     mutable QMutex mutex;
265
266 private:
267     // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.  
268     // Currently, locking is only necessary if the threaded loader is running concurrently.  If it is 
269     // either idle, or is running with the main thread blocked, no locking is necessary.  This way
270     // we only pay for locking when we have to.
271     // Consequently, this class should only be used to protect simple accesses or modifications of the 
272     // QQmlEnginePrivate structures or operations that can be guarenteed not to start activity
273     // on the loader thread.
274     // The Locker API is identical to QMutexLocker.  Locker reuses the QQmlEnginePrivate::mutex 
275     // QMutex instance and multiple Lockers are recursive in the same thread.
276     class Locker 
277     {
278     public:
279         inline Locker(const QQmlEngine *);
280         inline Locker(const QQmlEnginePrivate *);
281         inline ~Locker();
282
283         inline void unlock();
284         inline void relock();
285
286     private:
287         const QQmlEnginePrivate *m_ep;
288         quint32 m_locked:1;
289     };
290
291     // Must be called locked
292     QQmlPropertyCache *createCache(const QMetaObject *);
293     QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
294
295     // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
296     // the threaded loader.  Only access them through their respective accessor methods.
297     QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *> moduleApiInstances;
298     QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
299     QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
300     QHash<int, int> m_qmlLists;
301     QHash<int, QQmlCompiledData *> m_compositeTypes;
302
303     // These members is protected by the full QQmlEnginePrivate::mutex mutex
304     struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
305     QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
306     void doDeleteInEngineThread();
307 };
308
309 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
310 : m_ep(QQmlEnginePrivate::get(e))
311 {
312     relock();
313 }
314
315 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
316 : m_ep(e), m_locked(false)
317 {
318     relock();
319 }
320
321 QQmlEnginePrivate::Locker::~Locker()
322 {
323     unlock();
324 }
325
326 void QQmlEnginePrivate::Locker::unlock()
327 {
328     if (m_locked) { 
329         m_ep->mutex.unlock();
330         m_locked = false;
331     }
332 }
333
334 void QQmlEnginePrivate::Locker::relock()
335 {
336     Q_ASSERT(!m_locked);
337     if (m_ep->typeLoader.isConcurrent()) {
338         m_ep->mutex.lock();
339         m_locked = true;
340     }
341 }
342
343 /*!
344 Returns true if the calling thread is the QQmlEngine thread.
345 */
346 bool QQmlEnginePrivate::isEngineThread() const
347 {
348     Q_Q(const QQmlEngine);
349     return QThread::currentThread() == q->thread();
350 }
351
352 /*!
353 Returns true if the calling thread is the QQmlEngine \a engine thread.
354 */
355 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
356 {
357     Q_ASSERT(engine);
358     return QQmlEnginePrivate::get(engine)->isEngineThread();
359 }
360
361 /*!
362 Delete \a value in the engine thread.  If the calling thread is the engine
363 thread, \a value will be deleted immediately.
364
365 This method should be used for *any* type that has resources that need to
366 be freed in the engine thread.  This is generally types that use V8 handles.
367 As there is some small overhead in checking the current thread, it is best
368 practice to check if any V8 handles actually need to be freed and delete 
369 the instance directly if not.
370 */
371 template<typename T>
372 void QQmlEnginePrivate::deleteInEngineThread(T *value)
373 {
374     Q_Q(QQmlEngine);
375
376     Q_ASSERT(value);
377     if (isEngineThread()) {
378         delete value;
379     } else { 
380         struct I : public Deletable {
381             I(T *value) : value(value) {}
382             ~I() { delete value; }
383             T *value;
384         };
385         I *i = new I(value);
386         mutex.lock();
387         bool wasEmpty = toDeleteInEngineThread.isEmpty();
388         toDeleteInEngineThread.append(i);
389         mutex.unlock();
390         if (wasEmpty)
391             QCoreApplication::postEvent(q, new QEvent(QEvent::User));
392     }
393 }
394
395 /*!
396 Delete \a value in the \a engine thread.  If the calling thread is the engine
397 thread, \a value will be deleted immediately.
398 */
399 template<typename T>
400 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
401 {
402     Q_ASSERT(engine);
403     QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
404 }
405
406 /*!
407 Returns a QQmlPropertyCache for \a obj if one is available.
408
409 If \a obj is null, being deleted or contains a dynamic meta object 0
410 is returned.
411
412 The returned cache is not referenced, so if it is to be stored, call addref().
413
414 XXX thread There is a potential future race condition in this and all the cache()
415 functions.  As the QQmlPropertyCache is returned unreferenced, when called 
416 from the loader thread, it is possible that the cache will have been dereferenced 
417 and deleted before the loader thread has a chance to use or reference it.  This
418 can't currently happen as the cache holds a reference to the 
419 QQmlPropertyCache until the QQmlEngine is destroyed.
420 */
421 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
422 {
423     if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
424         return 0;
425
426     Locker locker(this);
427     const QMetaObject *mo = obj->metaObject();
428     QQmlPropertyCache *rv = propertyCache.value(mo);
429     if (!rv) rv = createCache(mo);
430     return rv;
431 }
432
433 /*!
434 Returns a QQmlPropertyCache for \a metaObject.
435
436 As the cache is persisted for the life of the engine, \a metaObject must be
437 a static "compile time" meta-object, or a meta-object that is otherwise known to
438 exist for the lifetime of the QQmlEngine.
439
440 The returned cache is not referenced, so if it is to be stored, call addref().
441 */
442 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
443 {
444     Q_ASSERT(metaObject);
445
446     Locker locker(this);
447     QQmlPropertyCache *rv = propertyCache.value(metaObject);
448     if (!rv) rv = createCache(metaObject);
449     return rv;
450 }
451
452 /*!
453 Returns a QQmlPropertyCache for \a type with \a minorVersion.
454
455 The returned cache is not referenced, so if it is to be stored, call addref().
456 */
457 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
458 {
459     Q_ASSERT(type);
460
461     if (minorVersion == -1 || !type->containsRevisionedAttributes())
462         return cache(type->metaObject());
463
464     Locker locker(this);
465     QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
466     if (!rv) rv = createCache(type, minorVersion, error);
467     return rv;
468 }
469
470 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e) 
471
472     return e->d_func()->v8engine(); 
473 }
474
475 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e) 
476
477     return e->d_func(); 
478 }
479
480 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e) 
481
482     return e->d_func(); 
483 }
484
485 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c) 
486
487     return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0; 
488 }
489
490 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c) 
491
492     return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0; 
493 }
494
495 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p) 
496
497     return p->q_func(); 
498 }
499
500 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
501 {
502     if (propertyCapture)
503         propertyCapture->captureProperty(n);
504 }
505
506 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
507 {
508     if (propertyCapture)
509         propertyCapture->captureProperty(o, c, n);
510 }
511
512 QT_END_NAMESPACE
513
514 #endif // QQMLENGINE_P_H