Implement strict mode for qmldir modules
[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     QQmlValueTypeFactory valueTypes;
204
205     // Unfortunate workaround to avoid a circular dependency between 
206     // qqmlengine_p.h and qqmlincubator_p.h
207     struct Incubator {
208         QIntrusiveListNode next;
209         // Unfortunate workaround for MSVC
210         QIntrusiveListNode nextWaitingFor;
211     };
212     QIntrusiveList<Incubator, &Incubator::next> incubatorList;
213     unsigned int incubatorCount;
214     QQmlIncubationController *incubationController;
215     void incubate(QQmlIncubator &, QQmlContextData *);
216
217     // These methods may be called from any thread
218     inline bool isEngineThread() const;
219     inline static bool isEngineThread(const QQmlEngine *);
220     template<typename T>
221     inline void deleteInEngineThread(T *);
222     template<typename T>
223     inline static void deleteInEngineThread(QQmlEngine *, T *);
224
225     // These methods may be called from the loader thread
226     QQmlMetaType::ModuleApiInstance *moduleApiInstance(const QQmlMetaType::ModuleApi &module);
227
228     // These methods may be called from the loader thread
229     inline QQmlPropertyCache *cache(QObject *obj);
230     inline QQmlPropertyCache *cache(const QMetaObject *);
231     inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error);
232
233     // These methods may be called from the loader thread
234     bool isQObject(int);
235     QObject *toQObject(const QVariant &, bool *ok = 0) const;
236     QQmlMetaType::TypeCategory typeCategory(int) const;
237     bool isList(int) const;
238     int listType(int) const;
239     QQmlMetaObject rawMetaObjectForType(int) const;
240     QQmlMetaObject metaObjectForType(int) const;
241     QQmlPropertyCache *propertyCacheForType(int);
242     QQmlPropertyCache *rawPropertyCacheForType(int);
243     void registerCompositeType(QQmlCompiledData *);
244     void unregisterCompositeType(QQmlCompiledData *);
245
246     bool isTypeLoaded(const QUrl &url) const;
247     bool isScriptLoaded(const QUrl &url) const;
248
249     inline void setDebugChangesCache(const QHash<QUrl, QByteArray> &changes);
250     inline QHash<QUrl, QByteArray> debugChangesCache();
251
252     void sendQuit();
253     void warning(const QQmlError &);
254     void warning(const QList<QQmlError> &);
255     void warning(QQmlDelayedError *);
256     static void warning(QQmlEngine *, const QQmlError &);
257     static void warning(QQmlEngine *, const QList<QQmlError> &);
258     static void warning(QQmlEngine *, QQmlDelayedError *);
259     static void warning(QQmlEnginePrivate *, const QQmlError &);
260     static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
261
262     inline static QV8Engine *getV8Engine(QQmlEngine *e);
263     inline static QQmlEnginePrivate *get(QQmlEngine *e);
264     inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
265     inline static QQmlEnginePrivate *get(QQmlContext *c);
266     inline static QQmlEnginePrivate *get(QQmlContextData *c);
267     inline static QQmlEngine *get(QQmlEnginePrivate *p);
268
269     static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
270     static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor);
271     static void defineQtQuick2Module();
272
273     static bool qml_debugging_enabled;
274
275     mutable QMutex mutex;
276
277 private:
278     // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.  
279     // Currently, locking is only necessary if the threaded loader is running concurrently.  If it is 
280     // either idle, or is running with the main thread blocked, no locking is necessary.  This way
281     // we only pay for locking when we have to.
282     // Consequently, this class should only be used to protect simple accesses or modifications of the 
283     // QQmlEnginePrivate structures or operations that can be guarenteed not to start activity
284     // on the loader thread.
285     // The Locker API is identical to QMutexLocker.  Locker reuses the QQmlEnginePrivate::mutex 
286     // QMutex instance and multiple Lockers are recursive in the same thread.
287     class Locker 
288     {
289     public:
290         inline Locker(const QQmlEngine *);
291         inline Locker(const QQmlEnginePrivate *);
292         inline ~Locker();
293
294         inline void unlock();
295         inline void relock();
296
297     private:
298         const QQmlEnginePrivate *m_ep;
299         quint32 m_locked:1;
300     };
301
302     // Must be called locked
303     QQmlPropertyCache *createCache(const QMetaObject *);
304     QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error);
305
306     // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
307     // the threaded loader.  Only access them through their respective accessor methods.
308     QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *> moduleApiInstances;
309     QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
310     QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache;
311     QHash<int, int> m_qmlLists;
312     QHash<int, QQmlCompiledData *> m_compositeTypes;
313     QHash<QUrl, QByteArray> debugChangesHash;
314
315     // These members is protected by the full QQmlEnginePrivate::mutex mutex
316     struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; };
317     QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
318     void doDeleteInEngineThread();
319 };
320
321 QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e)
322 : m_ep(QQmlEnginePrivate::get(e))
323 {
324     relock();
325 }
326
327 QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e)
328 : m_ep(e), m_locked(false)
329 {
330     relock();
331 }
332
333 QQmlEnginePrivate::Locker::~Locker()
334 {
335     unlock();
336 }
337
338 void QQmlEnginePrivate::Locker::unlock()
339 {
340     if (m_locked) { 
341         m_ep->mutex.unlock();
342         m_locked = false;
343     }
344 }
345
346 void QQmlEnginePrivate::Locker::relock()
347 {
348     Q_ASSERT(!m_locked);
349     if (m_ep->typeLoader.isConcurrent()) {
350         m_ep->mutex.lock();
351         m_locked = true;
352     }
353 }
354
355 /*!
356 Returns true if the calling thread is the QQmlEngine thread.
357 */
358 bool QQmlEnginePrivate::isEngineThread() const
359 {
360     Q_Q(const QQmlEngine);
361     return QThread::currentThread() == q->thread();
362 }
363
364 /*!
365 Returns true if the calling thread is the QQmlEngine \a engine thread.
366 */
367 bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
368 {
369     Q_ASSERT(engine);
370     return QQmlEnginePrivate::get(engine)->isEngineThread();
371 }
372
373 /*!
374 Delete \a value in the engine thread.  If the calling thread is the engine
375 thread, \a value will be deleted immediately.
376
377 This method should be used for *any* type that has resources that need to
378 be freed in the engine thread.  This is generally types that use V8 handles.
379 As there is some small overhead in checking the current thread, it is best
380 practice to check if any V8 handles actually need to be freed and delete 
381 the instance directly if not.
382 */
383 template<typename T>
384 void QQmlEnginePrivate::deleteInEngineThread(T *value)
385 {
386     Q_Q(QQmlEngine);
387
388     Q_ASSERT(value);
389     if (isEngineThread()) {
390         delete value;
391     } else { 
392         struct I : public Deletable {
393             I(T *value) : value(value) {}
394             ~I() { delete value; }
395             T *value;
396         };
397         I *i = new I(value);
398         mutex.lock();
399         bool wasEmpty = toDeleteInEngineThread.isEmpty();
400         toDeleteInEngineThread.append(i);
401         mutex.unlock();
402         if (wasEmpty)
403             QCoreApplication::postEvent(q, new QEvent(QEvent::User));
404     }
405 }
406
407 /*!
408 Delete \a value in the \a engine thread.  If the calling thread is the engine
409 thread, \a value will be deleted immediately.
410 */
411 template<typename T>
412 void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value)
413 {
414     Q_ASSERT(engine);
415     QQmlEnginePrivate::get(engine)->deleteInEngineThread<T>(value);
416 }
417
418 /*!
419 Returns a QQmlPropertyCache for \a obj if one is available.
420
421 If \a obj is null, being deleted or contains a dynamic meta object 0
422 is returned.
423
424 The returned cache is not referenced, so if it is to be stored, call addref().
425
426 XXX thread There is a potential future race condition in this and all the cache()
427 functions.  As the QQmlPropertyCache is returned unreferenced, when called 
428 from the loader thread, it is possible that the cache will have been dereferenced 
429 and deleted before the loader thread has a chance to use or reference it.  This
430 can't currently happen as the cache holds a reference to the 
431 QQmlPropertyCache until the QQmlEngine is destroyed.
432 */
433 QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj)
434 {
435     if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
436         return 0;
437
438     Locker locker(this);
439     const QMetaObject *mo = obj->metaObject();
440     QQmlPropertyCache *rv = propertyCache.value(mo);
441     if (!rv) rv = createCache(mo);
442     return rv;
443 }
444
445 /*!
446 Returns a QQmlPropertyCache for \a metaObject.
447
448 As the cache is persisted for the life of the engine, \a metaObject must be
449 a static "compile time" meta-object, or a meta-object that is otherwise known to
450 exist for the lifetime of the QQmlEngine.
451
452 The returned cache is not referenced, so if it is to be stored, call addref().
453 */
454 QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject)
455 {
456     Q_ASSERT(metaObject);
457
458     Locker locker(this);
459     QQmlPropertyCache *rv = propertyCache.value(metaObject);
460     if (!rv) rv = createCache(metaObject);
461     return rv;
462 }
463
464 /*!
465 Returns a QQmlPropertyCache for \a type with \a minorVersion.
466
467 The returned cache is not referenced, so if it is to be stored, call addref().
468 */
469 QQmlPropertyCache *QQmlEnginePrivate::cache(QQmlType *type, int minorVersion, QQmlError &error)
470 {
471     Q_ASSERT(type);
472
473     if (minorVersion == -1 || !type->containsRevisionedAttributes())
474         return cache(type->metaObject());
475
476     Locker locker(this);
477     QQmlPropertyCache *rv = typePropertyCache.value(qMakePair(type, minorVersion));
478     if (!rv) rv = createCache(type, minorVersion, error);
479     return rv;
480 }
481
482 QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e) 
483
484     Q_ASSERT(e);
485
486     return e->d_func()->v8engine(); 
487 }
488
489 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e) 
490
491     Q_ASSERT(e);
492
493     return e->d_func();
494 }
495
496 const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e) 
497
498     Q_ASSERT(e);
499
500     return e->d_func();
501 }
502
503 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c) 
504
505     return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : 0; 
506 }
507
508 QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c) 
509
510     return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : 0; 
511 }
512
513 QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p) 
514
515     Q_ASSERT(p);
516
517     return p->q_func(); 
518 }
519
520 void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
521 {
522     if (propertyCapture)
523         propertyCapture->captureProperty(n);
524 }
525
526 void QQmlEnginePrivate::captureProperty(QObject *o, int c, int n)
527 {
528     if (propertyCapture)
529         propertyCapture->captureProperty(o, c, n);
530 }
531
532 void QQmlEnginePrivate::setDebugChangesCache(const QHash<QUrl, QByteArray> &changes)
533 {
534     Locker locker(this);
535     foreach (const QUrl &key, changes.keys())
536         debugChangesHash.insert(key, changes.value(key));
537 }
538
539 QHash<QUrl, QByteArray> QQmlEnginePrivate::debugChangesCache()
540 {
541     Locker locker(this);
542     return debugChangesHash;
543 }
544
545 QT_END_NAMESPACE
546
547 #endif // QQMLENGINE_P_H