e014cfffc4e1716b9843e1b4f790998bfe9af25a
[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 qqmljavascriptexpression_p.h
107 class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint
108 {
109 public:
110     inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *);
111
112     static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e,
113                                                              QQmlEngine *engine);
114     inline void Delete();
115
116     QQmlJavaScriptExpression *expression;
117     QQmlJavaScriptExpressionGuard *next;
118 };
119
120 class Q_QML_PRIVATE_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
121 {
122     Q_DECLARE_PUBLIC(QQmlEngine)
123 public:
124     QQmlEnginePrivate(QQmlEngine *);
125     ~QQmlEnginePrivate();
126
127     void init();
128
129     class PropertyCapture {
130     public:
131         inline virtual ~PropertyCapture() {}
132         virtual void captureProperty(QQmlNotifier *) = 0;
133         virtual void captureProperty(QObject *, int, int) = 0;
134     };
135
136     PropertyCapture *propertyCapture;
137     inline void captureProperty(QQmlNotifier *);
138     inline void captureProperty(QObject *, int, int);
139
140     QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
141
142     QQmlContext *rootContext;
143     bool isDebugging;
144
145     bool outputWarningsToStdErr;
146
147     QQmlContextData *sharedContext;
148     QObject *sharedScope;
149
150     // Registered cleanup handlers
151     QQmlCleanup *cleanup;
152
153     // Bindings that have had errors during startup
154     QQmlDelayedError *erroredBindings;
155     int inProgressCreations;
156
157     QV8Engine *v8engine() const { return q_func()->handle(); }
158
159     QQuickWorkerScriptEngine *getWorkerScriptEngine();
160     QQuickWorkerScriptEngine *workerScriptEngine;
161
162     QUrl baseUrl;
163
164     typedef QPair<QQmlGuard<QObject>,int> FinalizeCallback;
165     void registerFinalizeCallback(QObject *obj, int index);
166
167     QQmlVME *activeVME;
168
169     QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
170     QNetworkAccessManager *getNetworkAccessManager() const;
171     mutable QNetworkAccessManager *networkAccessManager;
172     mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
173
174     QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
175
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 {
183     public:
184         ScarceResourceData(const QVariant &data) : data(data) {}
185         QVariant data;
186         QIntrusiveListNode node;
187     };
188     QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
189     int scarceResourcesRefCount;
190     void referenceScarceResources();
191     void dereferenceScarceResources();
192
193     QQmlTypeLoader typeLoader;
194     QQmlImportDatabase importDatabase;
195
196     QString offlineStoragePath;
197
198     mutable quint32 uniqueId;
199     inline quint32 getUniqueId() const {
200         return uniqueId++;
201     }
202
203     // Unfortunate workaround to avoid a circular dependency between 
204     // qqmlengine_p.h and qqmlincubator_p.h
205     struct Incubator {
206         QIntrusiveListNode next;
207         // Unfortunate workaround for MSVC
208         QIntrusiveListNode nextWaitingFor;
209     };
210     QIntrusiveList<Incubator, &Incubator::next> incubatorList;
211     unsigned int incubatorCount;
212     QQmlIncubationController *incubationController;
213     void incubate(QQmlIncubator &, QQmlContextData *);
214
215     // These methods may be called from any thread
216     inline bool isEngineThread() const;
217     inline static bool isEngineThread(const QQmlEngine *);
218     template<typename T>
219     inline void deleteInEngineThread(T *);
220     template<typename T>
221     inline static void deleteInEngineThread(QQmlEngine *, T *);
222
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);
227
228     // These methods may be called from the loader thread
229     bool isQObject(int);
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 *);
240
241     bool isTypeLoaded(const QUrl &url) const;
242     bool isScriptLoaded(const QUrl &url) const;
243
244     inline void setDebugChangesCache(const QHash<QUrl, QByteArray> &changes);
245     inline QHash<QUrl, QByteArray> debugChangesCache();
246
247     void sendQuit();
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> &);
256
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);
263
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();
267
268     static bool qml_debugging_enabled;
269
270     mutable QMutex mutex;
271
272 private:
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.
282     class Locker 
283     {
284     public:
285         inline Locker(const QQmlEngine *);
286         inline Locker(const QQmlEnginePrivate *);
287         inline ~Locker();
288
289         inline void unlock();
290         inline void relock();
291
292     private:
293         const QQmlEnginePrivate *m_ep;
294         quint32 m_locked:1;
295     };
296
297     // Must be called locked
298     QQmlPropertyCache *createCache(const QMetaObject *);
299     QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
300
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;
308
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();
313 };
314
315 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
316 : m_ep(QQmlEnginePrivate::get(e))
317 {
318     relock();
319 }
320
321 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
322 : m_ep(e), m_locked(false)
323 {
324     relock();
325 }
326
327 QQmlEnginePrivate::Locker::~Locker()
328 {
329     unlock();
330 }
331
332 void QQmlEnginePrivate::Locker::unlock()
333 {
334     if (m_locked) { 
335         m_ep->mutex.unlock();
336         m_locked = false;
337     }
338 }
339
340 void QQmlEnginePrivate::Locker::relock()
341 {
342     Q_ASSERT(!m_locked);
343     if (m_ep->typeLoader.isConcurrent()) {
344         m_ep->mutex.lock();
345         m_locked = true;
346     }
347 }
348
349 /*!
350 Returns true if the calling thread is the QQmlEngine thread.
351 */
352 bool QQmlEnginePrivate::isEngineThread() const
353 {
354     Q_Q(const QQmlEngine);
355     return QThread::currentThread() == q->thread();
356 }
357
358 /*!
359 Returns true if the calling thread is the QQmlEngine \a engine thread.
360 */
361 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
362 {
363     Q_ASSERT(engine);
364     return QQmlEnginePrivate::get(engine)->isEngineThread();
365 }
366
367 /*!
368 Delete \a value in the engine thread.  If the calling thread is the engine
369 thread, \a value will be deleted immediately.
370
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.
376 */
377 template<typename T>
378 void QQmlEnginePrivate::deleteInEngineThread(T *value)
379 {
380     Q_Q(QQmlEngine);
381
382     Q_ASSERT(value);
383     if (isEngineThread()) {
384         delete value;
385     } else { 
386         struct I : public Deletable {
387             I(T *value) : value(value) {}
388             ~I() { delete value; }
389             T *value;
390         };
391         I *i = new I(value);
392         mutex.lock();
393         bool wasEmpty = toDeleteInEngineThread.isEmpty();
394         toDeleteInEngineThread.append(i);
395         mutex.unlock();
396         if (wasEmpty)
397             QCoreApplication::postEvent(q, new QEvent(QEvent::User));
398     }
399 }
400
401 /*!
402 Delete \a value in the \a engine thread.  If the calling thread is the engine
403 thread, \a value will be deleted immediately.
404 */
405 template<typename T>
406 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
407 {
408     Q_ASSERT(engine);
409     QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
410 }
411
412 /*!
413 Returns a QQmlPropertyCache for \a obj if one is available.
414
415 If \a obj is null, being deleted or contains a dynamic meta object 0
416 is returned.
417
418 The returned cache is not referenced, so if it is to be stored, call addref().
419
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.
426 */
427 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
428 {
429     if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
430         return 0;
431
432     Locker locker(this);
433     const QMetaObject *mo = obj->metaObject();
434     QQmlPropertyCache *rv = propertyCache.value(mo);
435     if (!rv) rv = createCache(mo);
436     return rv;
437 }
438
439 /*!
440 Returns a QQmlPropertyCache for \a metaObject.
441
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.
445
446 The returned cache is not referenced, so if it is to be stored, call addref().
447 */
448 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
449 {
450     Q_ASSERT(metaObject);
451
452     Locker locker(this);
453     QQmlPropertyCache *rv = propertyCache.value(metaObject);
454     if (!rv) rv = createCache(metaObject);
455     return rv;
456 }
457
458 /*!
459 Returns a QQmlPropertyCache for \a type with \a minorVersion.
460
461 The returned cache is not referenced, so if it is to be stored, call addref().
462 */
463 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
464 {
465     Q_ASSERT(type);
466
467     if (minorVersion == -1 || !type->containsRevisionedAttributes())
468         return cache(type->metaObject());
469
470     Locker locker(this);
471     QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
472     if (!rv) rv = createCache(type, minorVersion, error);
473     return rv;
474 }
475
476 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e) 
477
478     Q_ASSERT(e);
479
480     return e->d_func()->v8engine(); 
481 }
482
483 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e) 
484
485     Q_ASSERT(e);
486
487     return e->d_func();
488 }
489
490 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e) 
491
492     Q_ASSERT(e);
493
494     return e->d_func();
495 }
496
497 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c) 
498
499     return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0; 
500 }
501
502 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c) 
503
504     return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0; 
505 }
506
507 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p) 
508
509     Q_ASSERT(p);
510
511     return p->q_func(); 
512 }
513
514 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
515 {
516     if (propertyCapture)
517         propertyCapture->captureProperty(n);
518 }
519
520 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
521 {
522     if (propertyCapture)
523         propertyCapture->captureProperty(o, c, n);
524 }
525
526 void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes)
527 {
528     Locker locker(this);
529     foreach (const QUrl &key, changes.keys())
530         debugChangesHash.insert(key, changes.value(key));
531 }
532
533 QHash<QUrl, QByteArray> QQmlEnginePrivate::debugChangesCache()
534 {
535     Locker locker(this);
536     return debugChangesHash;
537 }
538
539 QT_END_NAMESPACE
540
541 #endif // QQMLENGINE_P_H