Inspector:Modified Apply changes on Save for unsync. 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 *, 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     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     static void warning(QQmlEngine *, const QQmlError &);
251     static void warning(QQmlEngine *, const QList<QQmlError> &);
252     static void warning(QQmlEnginePrivate *, const QQmlError &);
253     static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
254
255     inline static QV8Engine *getV8Engine(QQmlEngine *e);
256     inline static QQmlEnginePrivate *get(QQmlEngine *e);
257     inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
258     inline static QQmlEnginePrivate *get(QQmlContext *c);
259     inline static QQmlEnginePrivate *get(QQmlContextData *c);
260     inline static QQmlEngine *get(QQmlEnginePrivate *p);
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     QHash<QUrl, QByteArray> debugChangesHash;
306
307     // These members is protected by the full QQmlEnginePrivate::mutex mutex
308     struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
309     QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
310     void doDeleteInEngineThread();
311 };
312
313 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
314 : m_ep(QQmlEnginePrivate::get(e))
315 {
316     relock();
317 }
318
319 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
320 : m_ep(e), m_locked(false)
321 {
322     relock();
323 }
324
325 QQmlEnginePrivate::Locker::~Locker()
326 {
327     unlock();
328 }
329
330 void QQmlEnginePrivate::Locker::unlock()
331 {
332     if (m_locked) { 
333         m_ep->mutex.unlock();
334         m_locked = false;
335     }
336 }
337
338 void QQmlEnginePrivate::Locker::relock()
339 {
340     Q_ASSERT(!m_locked);
341     if (m_ep->typeLoader.isConcurrent()) {
342         m_ep->mutex.lock();
343         m_locked = true;
344     }
345 }
346
347 /*!
348 Returns true if the calling thread is the QQmlEngine thread.
349 */
350 bool QQmlEnginePrivate::isEngineThread() const
351 {
352     Q_Q(const QQmlEngine);
353     return QThread::currentThread() == q->thread();
354 }
355
356 /*!
357 Returns true if the calling thread is the QQmlEngine \a engine thread.
358 */
359 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
360 {
361     Q_ASSERT(engine);
362     return QQmlEnginePrivate::get(engine)->isEngineThread();
363 }
364
365 /*!
366 Delete \a value in the engine thread.  If the calling thread is the engine
367 thread, \a value will be deleted immediately.
368
369 This method should be used for *any* type that has resources that need to
370 be freed in the engine thread.  This is generally types that use V8 handles.
371 As there is some small overhead in checking the current thread, it is best
372 practice to check if any V8 handles actually need to be freed and delete 
373 the instance directly if not.
374 */
375 template<typename T>
376 void QQmlEnginePrivate::deleteInEngineThread(T *value)
377 {
378     Q_Q(QQmlEngine);
379
380     Q_ASSERT(value);
381     if (isEngineThread()) {
382         delete value;
383     } else { 
384         struct I : public Deletable {
385             I(T *value) : value(value) {}
386             ~I() { delete value; }
387             T *value;
388         };
389         I *i = new I(value);
390         mutex.lock();
391         bool wasEmpty = toDeleteInEngineThread.isEmpty();
392         toDeleteInEngineThread.append(i);
393         mutex.unlock();
394         if (wasEmpty)
395             QCoreApplication::postEvent(q, new QEvent(QEvent::User));
396     }
397 }
398
399 /*!
400 Delete \a value in the \a engine thread.  If the calling thread is the engine
401 thread, \a value will be deleted immediately.
402 */
403 template<typename T>
404 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
405 {
406     Q_ASSERT(engine);
407     QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
408 }
409
410 /*!
411 Returns a QQmlPropertyCache for \a obj if one is available.
412
413 If \a obj is null, being deleted or contains a dynamic meta object 0
414 is returned.
415
416 The returned cache is not referenced, so if it is to be stored, call addref().
417
418 XXX thread There is a potential future race condition in this and all the cache()
419 functions.  As the QQmlPropertyCache is returned unreferenced, when called 
420 from the loader thread, it is possible that the cache will have been dereferenced 
421 and deleted before the loader thread has a chance to use or reference it.  This
422 can't currently happen as the cache holds a reference to the 
423 QQmlPropertyCache until the QQmlEngine is destroyed.
424 */
425 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
426 {
427     if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
428         return 0;
429
430     Locker locker(this);
431     const QMetaObject *mo = obj->metaObject();
432     QQmlPropertyCache *rv = propertyCache.value(mo);
433     if (!rv) rv = createCache(mo);
434     return rv;
435 }
436
437 /*!
438 Returns a QQmlPropertyCache for \a metaObject.
439
440 As the cache is persisted for the life of the engine, \a metaObject must be
441 a static "compile time" meta-object, or a meta-object that is otherwise known to
442 exist for the lifetime of the QQmlEngine.
443
444 The returned cache is not referenced, so if it is to be stored, call addref().
445 */
446 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
447 {
448     Q_ASSERT(metaObject);
449
450     Locker locker(this);
451     QQmlPropertyCache *rv = propertyCache.value(metaObject);
452     if (!rv) rv = createCache(metaObject);
453     return rv;
454 }
455
456 /*!
457 Returns a QQmlPropertyCache for \a type with \a minorVersion.
458
459 The returned cache is not referenced, so if it is to be stored, call addref().
460 */
461 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
462 {
463     Q_ASSERT(type);
464
465     if (minorVersion == -1 || !type->containsRevisionedAttributes())
466         return cache(type->metaObject());
467
468     Locker locker(this);
469     QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
470     if (!rv) rv = createCache(type, minorVersion, error);
471     return rv;
472 }
473
474 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e) 
475
476     Q_ASSERT(e);
477
478     return e->d_func()->v8engine(); 
479 }
480
481 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e) 
482
483     Q_ASSERT(e);
484
485     return e->d_func();
486 }
487
488 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e) 
489
490     Q_ASSERT(e);
491
492     return e->d_func();
493 }
494
495 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c) 
496
497     return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0; 
498 }
499
500 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c) 
501
502     return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0; 
503 }
504
505 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p) 
506
507     Q_ASSERT(p);
508
509     return p->q_func(); 
510 }
511
512 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
513 {
514     if (propertyCapture)
515         propertyCapture->captureProperty(n);
516 }
517
518 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
519 {
520     if (propertyCapture)
521         propertyCapture->captureProperty(o, c, n);
522 }
523
524 void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes)
525 {
526     Locker locker(this);
527     foreach (const QUrl &key, changes.keys())
528         debugChangesHash.insert(key, changes.value(key));
529 }
530
531 QHash<QUrl, QByteArray> QQmlEnginePrivate::debugChangesCache()
532 {
533     Locker locker(this);
534     return debugChangesHash;
535 }
536
537 QT_END_NAMESPACE
538
539 #endif // QQMLENGINE_P_H