1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLDATABLOB_P_H
5#define QQMLDATABLOB_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qqmlrefcount_p.h>
19#include <private/qqmljsdiagnosticmessage_p.h>
20#include <private/qv4compileddata_p.h>
21
22#if QT_CONFIG(qml_network)
23#include <QtNetwork/qnetworkreply.h>
24#endif
25
26#include <QtQml/qqmlprivate.h>
27#include <QtQml/qqmlerror.h>
28#include <QtQml/qqmlabstracturlinterceptor.h>
29#include <QtQml/qqmlprivate.h>
30
31#include <QtCore/qdatetime.h>
32#include <QtCore/qfileinfo.h>
33#include <QtCore/qurl.h>
34
35QT_BEGIN_NAMESPACE
36
37class QQmlTypeLoader;
38class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCounted<QQmlDataBlob>
39{
40public:
41 using Ptr = QQmlRefPointer<QQmlDataBlob>;
42
43 enum Status {
44 Null, // Prior to QQmlTypeLoader::load()
45 Loading, // Prior to data being received and dataReceived() being called
46 WaitingForDependencies, // While there are outstanding addDependency()s
47 ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles
48 Complete, // Finished
49 Error // Error
50 };
51
52 enum Type { //Matched in QQmlAbstractUrlInterceptor
53 QmlFile = QQmlAbstractUrlInterceptor::QmlFile,
54 JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile,
55 QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile
56 };
57
58 QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
59 ~QQmlDataBlob() override;
60
61 void startLoading();
62
63 QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
64
65 Type type() const;
66
67 Status status() const;
68 bool isNull() const;
69 bool isLoading() const;
70 bool isWaiting() const;
71 bool isComplete() const;
72 bool isError() const;
73 bool isCompleteOrError() const;
74
75 qreal progress() const;
76
77 QUrl url() const;
78 QString urlString() const;
79 QUrl finalUrl() const;
80 QString finalUrlString() const;
81
82 QList<QQmlError> errors() const;
83
84 class SourceCodeData {
85 public:
86 QString readAll(QString *error) const;
87 QDateTime sourceTimeStamp() const;
88 bool exists() const;
89 bool isEmpty() const;
90 bool isValid() const
91 {
92 return hasInlineSourceCode || !fileInfo.filePath().isEmpty();
93 }
94
95 private:
96 friend class QQmlDataBlob;
97 friend class QQmlTypeLoader;
98 QString inlineSourceCode;
99 QFileInfo fileInfo;
100 bool hasInlineSourceCode = false;
101 };
102
103protected:
104 // Can be called from within callbacks
105 void setError(const QQmlError &);
106 void setError(const QList<QQmlError> &errors);
107 void setError(const QQmlJS::DiagnosticMessage &error);
108 void setError(const QString &description);
109 void addDependency(QQmlDataBlob *);
110
111 // Callbacks made in load thread
112 virtual void dataReceived(const SourceCodeData &) = 0;
113 virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) = 0;
114 virtual void done();
115#if QT_CONFIG(qml_network)
116 virtual void networkError(QNetworkReply::NetworkError);
117#endif
118 virtual void dependencyError(QQmlDataBlob *);
119 virtual void dependencyComplete(QQmlDataBlob *);
120 virtual void allDependenciesDone();
121
122 // Callbacks made in main thread
123 virtual void downloadProgressChanged(qreal);
124 virtual void completed();
125
126protected:
127 // Manager that is currently fetching data for me
128 QQmlTypeLoader *m_typeLoader;
129
130private:
131 friend class QQmlTypeLoader;
132 friend class QQmlTypeLoaderThread;
133
134 void tryDone();
135 void cancelAllWaitingFor();
136 void notifyAllWaitingOnMe();
137 void notifyComplete(QQmlDataBlob *);
138
139 struct ThreadData {
140 private:
141 enum {
142 StatusMask = 0x0000FFFF,
143 StatusShift = 0,
144 ProgressMask = 0x00FF0000,
145 ProgressShift = 16,
146 AsyncMask = 0x80000000,
147 NoMask = 0
148 };
149
150 public:
151 inline ThreadData()
152 : _p(0)
153 {
154 }
155
156 inline QQmlDataBlob::Status status() const
157 {
158 return QQmlDataBlob::Status((_p.loadRelaxed() & StatusMask) >> StatusShift);
159 }
160
161 inline void setStatus(QQmlDataBlob::Status status)
162 {
163 while (true) {
164 int d = _p.loadRelaxed();
165 int nd = (d & ~StatusMask) | ((status << StatusShift) & StatusMask);
166 if (d == nd || _p.testAndSetOrdered(expectedValue: d, newValue: nd)) return;
167 }
168 }
169
170 inline bool isAsync() const
171 {
172 return _p.loadRelaxed() & AsyncMask;
173 }
174
175 inline void setIsAsync(bool v)
176 {
177 while (true) {
178 int d = _p.loadRelaxed();
179 int nd = (d & ~AsyncMask) | (v ? AsyncMask : NoMask);
180 if (d == nd || _p.testAndSetOrdered(expectedValue: d, newValue: nd)) return;
181 }
182 }
183
184 inline qreal progress() const
185 {
186 return quint8((_p.loadRelaxed() & ProgressMask) >> ProgressShift) / float(0xFF);
187 }
188
189 inline void setProgress(qreal progress)
190 {
191 quint8 v = 0xFF * progress;
192 while (true) {
193 int d = _p.loadRelaxed();
194 int nd = (d & ~ProgressMask) | ((v << ProgressShift) & ProgressMask);
195 if (d == nd || _p.testAndSetOrdered(expectedValue: d, newValue: nd)) return;
196 }
197 }
198
199 private:
200 QAtomicInt _p;
201 };
202 ThreadData m_data;
203
204 // m_errors should *always* be written before the status is set to Error.
205 // We use the status change as a memory fence around m_errors so that locking
206 // isn't required. Once the status is set to Error (or Complete), m_errors
207 // cannot be changed.
208 QList<QQmlError> m_errors;
209
210 Type m_type;
211
212 QUrl m_url;
213 QUrl m_finalUrl;
214 mutable QString m_urlString;
215 mutable QString m_finalUrlString;
216
217 // List of QQmlDataBlob's that are waiting for me to complete.
218protected:
219 QList<QQmlDataBlob *> m_waitingOnMe;
220private:
221
222 // List of QQmlDataBlob's that I am waiting for to complete.
223 QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
224
225 int m_redirectCount:30;
226 bool m_inCallback:1;
227 bool m_isDone:1;
228};
229
230QT_END_NAMESPACE
231
232#endif // QQMLDATABLOB_P_H
233

source code of qtdeclarative/src/qml/qml/qqmldatablob_p.h