1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #ifndef QQMLTYPELOADER_P_H
43 #define QQMLTYPELOADER_P_H
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.
56 #include <QtCore/qobject.h>
57 #include <QtCore/qatomic.h>
58 #include <QtNetwork/qnetworkreply.h>
59 #include <QtQml/qqmlerror.h>
60 #include <QtQml/qqmlengine.h>
61 #include <QtQml/qqmlfile.h>
63 #include <private/qv8_p.h>
64 #include <private/qhashedstring_p.h>
65 #include <private/qqmlscript_p.h>
66 #include <private/qqmlimport_p.h>
67 #include <private/qqmlcleanup_p.h>
68 #include <private/qqmldirparser_p.h>
69 #include <private/qqmlbundle_p.h>
70 #include <private/qflagpointer_p.h>
78 class QQmlCompiledData;
79 class QQmlComponentPrivate;
82 class QQmlExtensionInterface;
84 class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
88 Null, // Prior to QQmlDataLoader::load()
89 Loading, // Prior to data being received and dataReceived() being called
90 WaitingForDependencies, // While there are outstanding addDependency()s
101 QQmlDataBlob(const QUrl &, Type);
102 virtual ~QQmlDataBlob();
106 Status status() const;
108 bool isLoading() const;
109 bool isWaiting() const;
110 bool isComplete() const;
111 bool isError() const;
112 bool isCompleteOrError() const;
114 qreal progress() const;
117 QUrl finalUrl() const;
118 QString finalUrlString() const;
120 QList<QQmlError> errors() const;
124 inline const char *data() const;
125 inline int size() const;
127 inline QByteArray asByteArray() const;
129 inline bool isFile() const;
130 inline QQmlFile *asFile() const;
133 friend class QQmlDataBlob;
134 friend class QQmlDataLoader;
137 Data &operator=(const Data &);
138 QBiPointer<const QByteArray, QQmlFile> d;
142 // Can be called from within callbacks
143 void setError(const QQmlError &);
144 void setError(const QList<QQmlError> &errors);
145 void addDependency(QQmlDataBlob *);
147 // Callbacks made in load thread
148 virtual void dataReceived(const Data &) = 0;
150 virtual void networkError(QNetworkReply::NetworkError);
151 virtual void dependencyError(QQmlDataBlob *);
152 virtual void dependencyComplete(QQmlDataBlob *);
153 virtual void allDependenciesDone();
155 // Callbacks made in main thread
156 virtual void downloadProgressChanged(qreal);
157 virtual void completed();
159 friend class QQmlDataLoader;
160 friend class QQmlDataLoaderThread;
163 void cancelAllWaitingFor();
164 void notifyAllWaitingOnMe();
165 void notifyComplete(QQmlDataBlob *);
169 inline QQmlDataBlob::Status status() const;
170 inline void setStatus(QQmlDataBlob::Status);
171 inline bool isAsync() const;
172 inline void setIsAsync(bool);
173 inline quint8 progress() const;
174 inline void setProgress(quint8);
181 // m_errors should *always* be written before the status is set to Error.
182 // We use the status change as a memory fence around m_errors so that locking
183 // isn't required. Once the status is set to Error (or Complete), m_errors
184 // cannot be changed.
185 QList<QQmlError> m_errors;
191 mutable QString m_finalUrlString;
193 // List of QQmlDataBlob's that are waiting for me to complete.
194 QList<QQmlDataBlob *> m_waitingOnMe;
196 // List of QQmlDataBlob's that I am waiting for to complete.
197 QList<QQmlDataBlob *> m_waitingFor;
199 // Manager that is currently fetching data for me
200 QQmlDataLoader *m_manager;
201 int m_redirectCount:30;
206 class QQmlDataLoaderThread;
210 QQmlDataLoader(QQmlEngine *);
216 bool isConcurrent() const { return true; }
218 enum Mode { PreferSynchronous, Asynchronous };
220 void load(QQmlDataBlob *, Mode = PreferSynchronous);
221 void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
223 QQmlEngine *engine() const;
224 void initializeEngine(QQmlExtensionInterface *, const char *);
227 friend class QQmlDataBlob;
228 friend class QQmlDataLoaderThread;
229 friend class QQmlDataLoaderNetworkReplyProxy;
231 void loadThread(QQmlDataBlob *);
232 void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
233 void networkReplyFinished(QNetworkReply *);
234 void networkReplyProgress(QNetworkReply *, qint64, qint64);
236 typedef QHash<QNetworkReply *, QQmlDataBlob *> NetworkReplies;
238 void setData(QQmlDataBlob *, const QByteArray &);
239 void setData(QQmlDataBlob *, QQmlFile *);
240 void setData(QQmlDataBlob *, const QQmlDataBlob::Data &);
242 QQmlEngine *m_engine;
243 QQmlDataLoaderThread *m_thread;
244 NetworkReplies m_networkReplies;
247 class QQmlBundleData : public QQmlBundle,
251 QQmlBundleData(const QString &);
255 class QQmlTypeLoader : public QQmlDataLoader
257 Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
259 QQmlTypeLoader(QQmlEngine *);
266 Q_DECLARE_FLAGS(Options, Option)
268 QQmlTypeData *getType(const QUrl &url, Mode mode = PreferSynchronous);
269 QQmlTypeData *getType(const QByteArray &, const QUrl &url, Options = None);
271 QQmlScriptBlob *getScript(const QUrl &);
272 QQmlQmldirData *getQmldir(const QUrl &);
274 QQmlBundleData *getBundle(const QString &);
275 QQmlBundleData *getBundle(const QHashedStringRef &);
276 void addBundle(const QString &, const QString &);
278 QString absoluteFilePath(const QString &path);
279 bool directoryExists(const QString &path);
280 const QQmlDirParser *qmlDirParser(const QString &filePath, const QString &uriHint, QString *outUrl);
285 bool isTypeLoaded(const QUrl &url) const;
286 bool isScriptLoaded(const QUrl &url) const;
289 void addBundleNoLock(const QString &, const QString &);
290 QString bundleIdForQmldir(const QString &qmldir, const QString &uriHint);
295 TypedCallback(T *object, void (T::*func)(QQmlTypeData *)) : o(object), mf(func) {}
297 static void redirect(void *arg, QQmlTypeData *type)
299 TypedCallback<T> *self = reinterpret_cast<TypedCallback<T> *>(arg);
300 ((self->o)->*(self->mf))(type);
305 void (T::*mf)(QQmlTypeData *);
308 struct DirParser : public QQmlDirParser { QString adjustedUrl; };
310 typedef QHash<QUrl, QQmlTypeData *> TypeCache;
311 typedef QHash<QUrl, QQmlScriptBlob *> ScriptCache;
312 typedef QHash<QUrl, QQmlQmldirData *> QmldirCache;
313 typedef QStringHash<bool> StringSet;
314 typedef QStringHash<StringSet*> ImportDirCache;
315 typedef QStringHash<DirParser*> ImportQmlDirCache;
316 typedef QStringHash<QQmlBundleData *> BundleCache;
317 typedef QStringHash<QString> QmldirBundleIdCache;
319 TypeCache m_typeCache;
320 ScriptCache m_scriptCache;
321 QmldirCache m_qmldirCache;
322 ImportDirCache m_importDirCache;
323 ImportQmlDirCache m_importQmlDirCache;
324 BundleCache m_bundleCache;
325 QmldirBundleIdCache m_qmldirBundleIdCache;
328 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlTypeLoader::Options)
330 class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlDataBlob
335 TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0) {}
337 QQmlScript::Location location;
341 QQmlTypeData *typeData;
344 struct ScriptReference
346 ScriptReference() : script(0) {}
348 QQmlScript::Location location;
350 QQmlScriptBlob *script;
354 friend class QQmlTypeLoader;
356 QQmlTypeData(const QUrl &, QQmlTypeLoader::Options, QQmlTypeLoader *);
361 QQmlTypeLoader *typeLoader() const;
363 const QQmlImports &imports() const;
364 const QQmlScript::Parser &parser() const;
366 const QList<TypeReference> &resolvedTypes() const;
367 const QList<ScriptReference> &resolvedScripts() const;
368 const QSet<QString> &namespaces() const;
370 QQmlCompiledData *compiledData() const;
372 // Used by QQmlComponent to get notifications
373 struct TypeDataCallback {
374 ~TypeDataCallback() {}
375 virtual void typeDataProgress(QQmlTypeData *, qreal) {}
376 virtual void typeDataReady(QQmlTypeData *) {}
378 void registerCallback(TypeDataCallback *);
379 void unregisterCallback(TypeDataCallback *);
383 virtual void completed();
384 virtual void dataReceived(const Data &);
385 virtual void allDependenciesDone();
386 virtual void downloadProgressChanged(qreal);
392 QQmlTypeLoader::Options m_options;
394 QQmlQmldirData *qmldirForUrl(const QUrl &);
396 QQmlScript::Parser scriptParser;
397 QQmlImports m_imports;
399 QList<ScriptReference> m_scripts;
400 QList<QQmlQmldirData *> m_qmldirs;
402 QSet<QString> m_namespaces;
404 QList<TypeReference> m_types;
405 bool m_typesResolved:1;
407 QQmlCompiledData *m_compiledData;
409 QList<TypeDataCallback *> m_callbacks;
411 QQmlTypeLoader *m_typeLoader;
414 // QQmlScriptData instances are created, uninitialized, by the loader in the
415 // load thread. The first time they are used by the VME, they are initialized which
416 // creates their v8 objects and they are referenced and added to the engine's cleanup
417 // list. During QQmlCleanup::clear() all v8 resources are destroyed, and the
418 // reference that was created is released but final deletion only occurs once all the
419 // references as released. This is all intended to ensure that the v8 resources are
420 // only created and destroyed in the main thread :)
421 class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup, public QQmlRefCount
424 friend class QQmlTypeLoader;
433 QQmlTypeNameCache *importCache;
434 QList<QQmlScriptBlob *> scripts;
435 QQmlScript::Object::ScriptBlock::Pragmas pragmas;
437 bool isInitialized() const { return hasEngine(); }
438 void initialize(QQmlEngine *);
441 virtual void clear(); // From QQmlCleanup
444 friend class QQmlVME;
445 friend class QQmlScriptBlob;
448 QByteArray m_programSource;
449 v8::Persistent<v8::Script> m_program;
450 v8::Persistent<v8::Object> m_value;
453 class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlDataBlob
456 friend class QQmlTypeLoader;
458 QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
463 struct ScriptReference
465 ScriptReference() : script(0) {}
467 QQmlScript::Location location;
470 QQmlScriptBlob *script;
473 QQmlScript::Object::ScriptBlock::Pragmas pragmas() const;
475 QQmlTypeLoader *typeLoader() const;
476 const QQmlImports &imports() const;
478 QQmlScriptData *scriptData() const;
481 virtual void dataReceived(const Data &);
485 QQmlScript::Object::ScriptBlock::Pragmas m_pragmas;
488 QQmlImports m_imports;
489 QList<ScriptReference> m_scripts;
490 QQmlScriptData *m_scriptData;
492 QQmlTypeLoader *m_typeLoader;
495 class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlDataBlob
498 friend class QQmlTypeLoader;
500 QQmlQmldirData(const QUrl &);
503 const QQmlDirComponents &dirComponents() const;
506 virtual void dataReceived(const Data &);
509 QQmlDirComponents m_components;
512 QQmlDataBlob::Data::Data()
516 const char *QQmlDataBlob::Data::data() const
518 Q_ASSERT(!d.isNull());
520 if (d.isT1()) return d.asT1()->constData();
521 else return d.asT2()->data();
524 int QQmlDataBlob::Data::size() const
526 Q_ASSERT(!d.isNull());
528 if (d.isT1()) return d.asT1()->size();
529 else return d.asT2()->size();
532 bool QQmlDataBlob::Data::isFile() const
537 QByteArray QQmlDataBlob::Data::asByteArray() const
539 Q_ASSERT(!d.isNull());
541 if (d.isT1()) return *d.asT1();
542 else return d.asT2()->dataByteArray();
545 QQmlFile *QQmlDataBlob::Data::asFile() const
547 if (d.isT2()) return d.asT2();
553 #endif // QQMLTYPELOADER_P_H