Merge branch 'master' of git://gitorious.org/qt/qtdeclarative into api_changes
[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 *);
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 QString urlToLocalFileOrQrc(const QUrl& url);
260     static QString urlToLocalFileOrQrc(const QString& url);
261
262     static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
263     static void defineModule();
264
265     static bool qml_debugging_enabled;
266
267     mutable QMutex mutex;
268
269 private:
270     // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.  
271     // Currently, locking is only necessary if the threaded loader is running concurrently.  If it is 
272     // either idle, or is running with the main thread blocked, no locking is necessary.  This way
273     // we only pay for locking when we have to.
274     // Consequently, this class should only be used to protect simple accesses or modifications of the 
275     // QQmlEnginePrivate structures or operations that can be guarenteed not to start activity
276     // on the loader thread.
277     // The Locker API is identical to QMutexLocker.  Locker reuses the QQmlEnginePrivate::mutex 
278     // QMutex instance and multiple Lockers are recursive in the same thread.
279     class Locker 
280     {
281     public:
282         inline Locker(const QQmlEngine *);
283         inline Locker(const QQmlEnginePrivate *);
284         inline ~Locker();
285
286         inline void unlock();
287         inline void relock();
288
289     private:
290         const QQmlEnginePrivate *m_ep;
291         quint32 m_locked:1;
292     };
293
294     // Must be called locked
295     QQmlPropertyCache *createCache(const QMetaObject *);
296     QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
297
298     // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
299     // the threaded loader.  Only access them through their respective accessor methods.
300     QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *> moduleApiInstances;
301     QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
302     QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
303     QHash<int, int> m_qmlLists;
304     QHash<int, QQmlCompiledData *> m_compositeTypes;
305
306     // These members is protected by the full QQmlEnginePrivate::mutex mutex
307     struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
308     QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
309     void doDeleteInEngineThread();
310 };
311
312 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
313 : m_ep(QQmlEnginePrivate::get(e))
314 {
315     relock();
316 }
317
318 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
319 : m_ep(e), m_locked(false)
320 {
321     relock();
322 }
323
324 QQmlEnginePrivate::Locker::~Locker()
325 {
326     unlock();
327 }
328
329 void QQmlEnginePrivate::Locker::unlock()
330 {
331     if (m_locked) { 
332         m_ep->mutex.unlock();
333         m_locked = false;
334     }
335 }
336
337 void QQmlEnginePrivate::Locker::relock()
338 {
339     Q_ASSERT(!m_locked);
340     if (m_ep->typeLoader.isConcurrent()) {
341         m_ep->mutex.lock();
342         m_locked = true;
343     }
344 }
345
346 /*!
347 Returns true if the calling thread is the QQmlEngine thread.
348 */
349 bool QQmlEnginePrivate::isEngineThread() const
350 {
351     Q_Q(const QQmlEngine);
352     return QThread::currentThread() == q->thread();
353 }
354
355 /*!
356 Returns true if the calling thread is the QQmlEngine \a engine thread.
357 */
358 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
359 {
360     Q_ASSERT(engine);
361     return QQmlEnginePrivate::get(engine)->isEngineThread();
362 }
363
364 /*!
365 Delete \a value in the engine thread.  If the calling thread is the engine
366 thread, \a value will be deleted immediately.
367
368 This method should be used for *any* type that has resources that need to
369 be freed in the engine thread.  This is generally types that use V8 handles.
370 As there is some small overhead in checking the current thread, it is best
371 practice to check if any V8 handles actually need to be freed and delete 
372 the instance directly if not.
373 */
374 template<typename T>
375 void QQmlEnginePrivate::deleteInEngineThread(T *value)
376 {
377     Q_Q(QQmlEngine);
378
379     Q_ASSERT(value);
380     if (isEngineThread()) {
381         delete value;
382     } else { 
383         struct I : public Deletable {
384             I(T *value) : value(value) {}
385             ~I() { delete value; }
386             T *value;
387         };
388         I *i = new I(value);
389         mutex.lock();
390         bool wasEmpty = toDeleteInEngineThread.isEmpty();
391         toDeleteInEngineThread.append(i);
392         mutex.unlock();
393         if (wasEmpty)
394             QCoreApplication::postEvent(q, new QEvent(QEvent::User));
395     }
396 }
397
398 /*!
399 Delete \a value in the \a engine thread.  If the calling thread is the engine
400 thread, \a value will be deleted immediately.
401 */
402 template<typename T>
403 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
404 {
405     Q_ASSERT(engine);
406     QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
407 }
408
409 /*!
410 Returns a QQmlPropertyCache for \a obj if one is available.
411
412 If \a obj is null, being deleted or contains a dynamic meta object 0
413 is returned.
414
415 The returned cache is not referenced, so if it is to be stored, call addref().
416
417 XXX thread There is a potential future race condition in this and all the cache()
418 functions.  As the QQmlPropertyCache is returned unreferenced, when called 
419 from the loader thread, it is possible that the cache will have been dereferenced 
420 and deleted before the loader thread has a chance to use or reference it.  This
421 can't currently happen as the cache holds a reference to the 
422 QQmlPropertyCache until the QQmlEngine is destroyed.
423 */
424 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
425 {
426     if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
427         return 0;
428
429     Locker locker(this);
430     const QMetaObject *mo = obj->metaObject();
431     QQmlPropertyCache *rv = propertyCache.value(mo);
432     if (!rv) rv = createCache(mo);
433     return rv;
434 }
435
436 /*!
437 Returns a QQmlPropertyCache for \a metaObject.
438
439 As the cache is persisted for the life of the engine, \a metaObject must be
440 a static "compile time" meta-object, or a meta-object that is otherwise known to
441 exist for the lifetime of the QQmlEngine.
442
443 The returned cache is not referenced, so if it is to be stored, call addref().
444 */
445 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
446 {
447     Q_ASSERT(metaObject);
448
449     Locker locker(this);
450     QQmlPropertyCache *rv = propertyCache.value(metaObject);
451     if (!rv) rv = createCache(metaObject);
452     return rv;
453 }
454
455 /*!
456 Returns a QQmlPropertyCache for \a type with \a minorVersion.
457
458 The returned cache is not referenced, so if it is to be stored, call addref().
459 */
460 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
461 {
462     Q_ASSERT(type);
463
464     if (minorVersion == -1 || !type->containsRevisionedAttributes())
465         return cache(type->metaObject());
466
467     Locker locker(this);
468     QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
469     if (!rv) rv = createCache(type, minorVersion, error);
470     return rv;
471 }
472
473 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e) 
474
475     return e->d_func()->v8engine(); 
476 }
477
478 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e) 
479
480     return e->d_func(); 
481 }
482
483 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e) 
484
485     return e->d_func(); 
486 }
487
488 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c) 
489
490     return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0; 
491 }
492
493 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c) 
494
495     return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0; 
496 }
497
498 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p) 
499
500     return p->q_func(); 
501 }
502
503 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
504 {
505     if (propertyCapture)
506         propertyCapture->captureProperty(n);
507 }
508
509 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
510 {
511     if (propertyCapture)
512         propertyCapture->captureProperty(o, c, n);
513 }
514
515 QT_END_NAMESPACE
516
517 #endif // QQMLENGINE_P_H