1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 void shutdownThread();
230 friend class QQmlDataBlob;
231 friend class QQmlDataLoaderThread;
232 friend class QQmlDataLoaderNetworkReplyProxy;
234 void loadThread(QQmlDataBlob *);
235 void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
236 void networkReplyFinished(QNetworkReply *);
237 void networkReplyProgress(QNetworkReply *, qint64, qint64);
239 typedef QHash<QNetworkReply *, QQmlDataBlob *> NetworkReplies;
241 void setData(QQmlDataBlob *, const QByteArray &);
242 void setData(QQmlDataBlob *, QQmlFile *);
243 void setData(QQmlDataBlob *, const QQmlDataBlob::Data &);
245 QQmlEngine *m_engine;
246 QQmlDataLoaderThread *m_thread;
247 NetworkReplies m_networkReplies;
250 class QQmlBundleData : public QQmlBundle,
254 QQmlBundleData(const QString &);
258 class QQmlTypeLoader : public QQmlDataLoader
260 Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
262 class Q_QML_PRIVATE_EXPORT Blob : public QQmlDataBlob
265 Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader);
268 QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
269 const QQmlImports &imports() const { return m_imports; }
272 bool addImport(const QQmlScript::Import &import, QList<QQmlError> *errors);
274 bool fetchQmldir(const QUrl &url, const QQmlScript::Import *import, int priority, QList<QQmlError> *errors);
275 bool updateQmldir(QQmlQmldirData *data, const QQmlScript::Import *import, QList<QQmlError> *errors);
278 virtual bool qmldirDataAvailable(QQmlQmldirData *, QList<QQmlError> *);
280 virtual void scriptImported(QQmlScriptBlob *, const QQmlScript::Location &, const QString &, const QString &) {}
282 virtual void dependencyError(QQmlDataBlob *);
283 virtual void dependencyComplete(QQmlDataBlob *);
286 QQmlTypeLoader *m_typeLoader;
287 QQmlImports m_imports;
288 QHash<const QQmlScript::Import *, int> m_unresolvedImports;
289 QList<QQmlQmldirData *> m_qmldirs;
295 friend class QQmlTypeLoader;
298 void setContent(const QString &location, const QString &content);
299 void setError(const QQmlError &);
302 bool hasError() const;
303 QList<QQmlError> errors(const QString &uri) const;
305 QString typeNamespace() const;
307 QQmlDirComponents components() const;
308 QQmlDirScripts scripts() const;
309 QQmlDirPlugins plugins() const;
311 QString pluginLocation() const;
314 QQmlDirParser m_parser;
318 QQmlTypeLoader(QQmlEngine *);
325 Q_DECLARE_FLAGS(Options, Option)
327 QQmlImportDatabase *importDatabase();
329 QQmlTypeData *getType(const QUrl &url, Mode mode = PreferSynchronous);
330 QQmlTypeData *getType(const QByteArray &, const QUrl &url, Options = None);
332 QQmlScriptBlob *getScript(const QUrl &);
333 QQmlQmldirData *getQmldir(const QUrl &);
335 QQmlBundleData *getBundle(const QString &);
336 QQmlBundleData *getBundle(const QHashedStringRef &);
337 void addBundle(const QString &, const QString &);
339 QString absoluteFilePath(const QString &path);
340 bool directoryExists(const QString &path);
342 const QmldirContent *qmldirContent(const QString &filePath, const QString &uriHint);
343 void setQmldirContent(const QString &filePath, const QString &content);
348 bool isTypeLoaded(const QUrl &url) const;
349 bool isScriptLoaded(const QUrl &url) const;
352 void addBundleNoLock(const QString &, const QString &);
353 QString bundleIdForQmldir(const QString &qmldir, const QString &uriHint);
358 TypedCallback(T *object, void (T::*func)(QQmlTypeData *)) : o(object), mf(func) {}
360 static void redirect(void *arg, QQmlTypeData *type)
362 TypedCallback<T> *self = reinterpret_cast<TypedCallback<T> *>(arg);
363 ((self->o)->*(self->mf))(type);
368 void (T::*mf)(QQmlTypeData *);
371 typedef QHash<QUrl, QQmlTypeData *> TypeCache;
372 typedef QHash<QUrl, QQmlScriptBlob *> ScriptCache;
373 typedef QHash<QUrl, QQmlQmldirData *> QmldirCache;
374 typedef QStringHash<bool> StringSet;
375 typedef QStringHash<StringSet*> ImportDirCache;
376 typedef QStringHash<QmldirContent *> ImportQmlDirCache;
377 typedef QStringHash<QQmlBundleData *> BundleCache;
378 typedef QStringHash<QString> QmldirBundleIdCache;
380 TypeCache m_typeCache;
381 ScriptCache m_scriptCache;
382 QmldirCache m_qmldirCache;
383 ImportDirCache m_importDirCache;
384 ImportQmlDirCache m_importQmlDirCache;
385 BundleCache m_bundleCache;
386 QmldirBundleIdCache m_qmldirBundleIdCache;
389 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlTypeLoader::Options)
391 class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
396 TypeReference() : type(0), majorVersion(0), minorVersion(0), typeData(0) {}
398 QQmlScript::Location location;
402 QQmlTypeData *typeData;
405 struct ScriptReference
407 ScriptReference() : script(0) {}
409 QQmlScript::Location location;
411 QQmlScriptBlob *script;
415 friend class QQmlTypeLoader;
417 QQmlTypeData(const QUrl &, QQmlTypeLoader::Options, QQmlTypeLoader *);
422 const QQmlScript::Parser &parser() const;
424 const QList<TypeReference> &resolvedTypes() const;
425 const QList<ScriptReference> &resolvedScripts() const;
426 const QSet<QString> &namespaces() const;
428 QQmlCompiledData *compiledData() const;
430 // Used by QQmlComponent to get notifications
431 struct TypeDataCallback {
432 virtual ~TypeDataCallback();
433 virtual void typeDataProgress(QQmlTypeData *, qreal) {}
434 virtual void typeDataReady(QQmlTypeData *) {}
436 void registerCallback(TypeDataCallback *);
437 void unregisterCallback(TypeDataCallback *);
441 virtual void completed();
442 virtual void dataReceived(const Data &);
443 virtual void allDependenciesDone();
444 virtual void downloadProgressChanged(qreal);
450 virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
452 QQmlTypeLoader::Options m_options;
454 QQmlScript::Parser scriptParser;
456 QList<ScriptReference> m_scripts;
458 QSet<QString> m_namespaces;
460 QList<TypeReference> m_types;
461 bool m_typesResolved:1;
463 QQmlCompiledData *m_compiledData;
465 QList<TypeDataCallback *> m_callbacks;
467 QQmlScript::Import *m_implicitImport;
470 // QQmlScriptData instances are created, uninitialized, by the loader in the
471 // load thread. The first time they are used by the VME, they are initialized which
472 // creates their v8 objects and they are referenced and added to the engine's cleanup
473 // list. During QQmlCleanup::clear() all v8 resources are destroyed, and the
474 // reference that was created is released but final deletion only occurs once all the
475 // references as released. This is all intended to ensure that the v8 resources are
476 // only created and destroyed in the main thread :)
477 class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup, public QQmlRefCount
480 friend class QQmlTypeLoader;
489 QQmlTypeNameCache *importCache;
490 QList<QQmlScriptBlob *> scripts;
491 QQmlScript::Object::ScriptBlock::Pragmas pragmas;
493 bool isInitialized() const { return hasEngine(); }
494 void initialize(QQmlEngine *);
496 bool hasError() const { return m_error.isValid(); }
497 void setError(const QQmlError &error) { m_error = error; }
498 QQmlError error() const { return m_error; }
501 virtual void clear(); // From QQmlCleanup
504 friend class QQmlVME;
505 friend class QQmlScriptBlob;
508 QByteArray m_programSource;
509 v8::Persistent<v8::Script> m_program;
510 v8::Persistent<v8::Object> m_value;
514 class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlTypeLoader::Blob
517 friend class QQmlTypeLoader;
519 QQmlScriptBlob(const QUrl &, QQmlTypeLoader *);
524 struct ScriptReference
526 ScriptReference() : script(0) {}
528 QQmlScript::Location location;
531 QQmlScriptBlob *script;
534 QQmlScript::Object::ScriptBlock::Pragmas pragmas() const;
536 QQmlScriptData *scriptData() const;
539 virtual void dataReceived(const Data &);
543 virtual void scriptImported(QQmlScriptBlob *blob, const QQmlScript::Location &location, const QString &qualifier, const QString &nameSpace);
546 QQmlScript::Parser::JavaScriptMetaData m_metadata;
548 QList<ScriptReference> m_scripts;
549 QQmlScriptData *m_scriptData;
552 class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob
555 friend class QQmlTypeLoader;
557 QQmlQmldirData(const QUrl &, QQmlTypeLoader *);
560 const QString &content() const;
562 const QQmlScript::Import *import() const;
563 void setImport(const QQmlScript::Import *);
565 int priority() const;
566 void setPriority(int);
569 virtual void dataReceived(const Data &);
573 const QQmlScript::Import *m_import;
577 QQmlDataBlob::Data::Data()
581 const char *QQmlDataBlob::Data::data() const
583 Q_ASSERT(!d.isNull());
585 if (d.isT1()) return d.asT1()->constData();
586 else return d.asT2()->data();
589 int QQmlDataBlob::Data::size() const
591 Q_ASSERT(!d.isNull());
593 if (d.isT1()) return d.asT1()->size();
594 else return d.asT2()->size();
597 bool QQmlDataBlob::Data::isFile() const
602 QByteArray QQmlDataBlob::Data::asByteArray() const
604 Q_ASSERT(!d.isNull());
606 if (d.isT1()) return *d.asT1();
607 else return d.asT2()->dataByteArray();
610 QQmlFile *QQmlDataBlob::Data::asFile() const
612 if (d.isT2()) return d.asT2();
618 #endif // QQMLTYPELOADER_P_H