Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmldatablob_p.h
Go to the documentation of this file.
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
21#if QT_CONFIG(qml_network)
22#include <QtNetwork/qnetworkreply.h>
23#endif
24
25#include <QtQml/qqmlprivate.h>
26#include <QtQml/qqmlerror.h>
27#include <QtQml/qqmlabstracturlinterceptor.h>
28#include <QtQml/qqmlprivate.h>
29
30#include <QtCore/qdatetime.h>
31#include <QtCore/qfileinfo.h>
32#include <QtCore/qurl.h>
33
34QT_BEGIN_NAMESPACE
35
36class QQmlTypeLoader;
37class Q_QML_EXPORT QQmlDataBlob : public QQmlRefCounted<QQmlDataBlob>
38{
39public:
40 using Ptr = QQmlRefPointer<QQmlDataBlob>;
41
42 enum Status {
43 Null, // Prior to QQmlTypeLoader::load()
44 Loading, // Prior to data being received and dataReceived() being called
45 WaitingForDependencies, // While there are outstanding addDependency()s
46 ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles
47 Complete, // Finished
48 Error // Error
49 };
50
51 enum Type { //Matched in QQmlAbstractUrlInterceptor
52 QmlFile = QQmlAbstractUrlInterceptor::QmlFile,
53 JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile,
54 QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile
55 };
56
57 QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
58 virtual ~QQmlDataBlob();
59
60 void startLoading();
61
62 QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
63 void resetTypeLoader() { m_typeLoader = nullptr; }
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 bool isAsync() const;
76 qreal progress() const;
77
78 QUrl url() const;
79 QString urlString() const;
80 QUrl finalUrl() const;
81 QString finalUrlString() const;
82
83 QList<QQmlError> errors() const;
84
85 class SourceCodeData {
86 public:
87 QString readAll(QString *error) const;
88 QDateTime sourceTimeStamp() const;
89 bool exists() const;
90 bool isEmpty() const;
91 bool isCacheable() const { return !hasStaticData; }
92 bool isValid() const
93 {
94 return hasInlineSourceCode || !fileInfo.filePath().isEmpty();
95 }
96
97 private:
98 friend class QQmlDataBlob;
99 friend class QQmlTypeLoader;
100 QString inlineSourceCode;
101 QFileInfo fileInfo;
102 bool hasInlineSourceCode = false;
103 bool hasStaticData = false;
104 };
105
106 template<typename Loader = QQmlTypeLoader>
107 void assertTypeLoaderThreadIfRunning() const
108 {
109 const Loader *loader = m_typeLoader;
110 Q_ASSERT(!loader || !loader->thread() || loader->thread()->isThisThread());
111 }
112
113 template<typename Loader = QQmlTypeLoader>
114 void assertTypeLoaderThread() const
115 {
116 const Loader *loader = m_typeLoader;
117 Q_ASSERT(loader && loader->thread() && loader->thread()->isThisThread());
118 }
119
120 template<typename Loader = QQmlTypeLoader>
121 void assertEngineThreadIfRunning() const
122 {
123 const Loader *loader = m_typeLoader;
124 Q_ASSERT(!loader || !loader->thread() || loader->thread()->isParentThread());
125 }
126
127 template<typename Loader = QQmlTypeLoader>
128 void assertEngineThread() const
129 {
130 const Loader *loader = m_typeLoader;
131 Q_ASSERT(loader && loader->thread() && loader->thread()->isParentThread());
132 }
133
134protected:
135 // Can be called from within callbacks
136 void setError(const QQmlError &);
137 void setError(const QList<QQmlError> &errors);
138 void setError(const QQmlJS::DiagnosticMessage &error);
139 void setError(const QString &description);
140 void addDependency(const QQmlDataBlob::Ptr &);
141
142 // Callbacks made in load thread
143 virtual void dataReceived(const SourceCodeData &) = 0;
144 virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) = 0;
145 virtual void done();
146#if QT_CONFIG(qml_network)
147 virtual void networkError(QNetworkReply::NetworkError);
148#endif
149 virtual void dependencyError(const QQmlDataBlob::Ptr &);
150 virtual void dependencyComplete(const QQmlDataBlob::Ptr &);
151 virtual void allDependenciesDone();
152
153 // Callbacks made in main thread
154 virtual void downloadProgressChanged(qreal);
155 virtual void completed();
156
157protected:
158 // Manager that is currently fetching data for me
159 QQmlTypeLoader *m_typeLoader;
160
161private:
162 friend class QQmlTypeLoader;
163 friend class QQmlTypeLoaderThread;
164
165 void tryDone();
166 void cancelAllWaitingFor();
167 void notifyAllWaitingOnMe();
168 void notifyComplete(const QQmlDataBlob::Ptr &);
169
170 bool setStatus(Status status);
171 bool setIsAsync(bool async) { return m_data.setIsAsync(async); }
172 bool setProgress(qreal progress) { return m_data.setProgress(progress); }
173
174 struct ThreadData {
175 public:
176 friend bool QQmlDataBlob::setStatus(Status);
177 friend bool QQmlDataBlob::setIsAsync(bool);
178 friend bool QQmlDataBlob::setProgress(qreal);
179
180 inline ThreadData()
181 : _p(0)
182 {
183 }
184
185 inline QQmlDataBlob::Status status() const
186 {
187 return QQmlDataBlob::Status((_p.loadAcquire() & StatusMask) >> StatusShift);
188 }
189
190 inline bool isAsync() const
191 {
192 return _p.loadAcquire() & AsyncMask;
193 }
194
195 inline qreal progress() const
196 {
197 return quint8((_p.loadAcquire() & ProgressMask) >> ProgressShift) / float(0xFF);
198 }
199
200 private:
201 enum {
202 StatusMask = 0x0000FFFF,
203 StatusShift = 0,
204 ProgressMask = 0x00FF0000,
205 ProgressShift = 16,
206 AsyncMask = 0x80000000,
207 NoMask = 0
208 };
209
210
211 inline bool setStatus(QQmlDataBlob::Status status)
212 {
213 while (true) {
214 int d = _p.loadAcquire();
215 int nd = (d & ~StatusMask) | ((status << StatusShift) & StatusMask);
216 if (d == nd)
217 return false;
218 if (_p.testAndSetRelease(d, nd))
219 return true;
220 }
221
222 Q_UNREACHABLE_RETURN(false);
223 }
224
225 inline bool setIsAsync(bool v)
226 {
227 while (true) {
228 int d = _p.loadAcquire();
229 int nd = (d & ~AsyncMask) | (v ? AsyncMask : NoMask);
230 if (d == nd)
231 return false;
232 if (_p.testAndSetRelease(d, nd))
233 return true;
234 }
235
236 Q_UNREACHABLE_RETURN(false);
237 }
238
239 inline bool setProgress(qreal progress)
240 {
241 quint8 v = 0xFF * progress;
242 while (true) {
243 int d = _p.loadAcquire();
244 int nd = (d & ~ProgressMask) | ((v << ProgressShift) & ProgressMask);
245 if (d == nd)
246 return false;
247 if (_p.testAndSetRelease(d, nd))
248 return true;
249 }
250 Q_UNREACHABLE_RETURN(false);
251 }
252
253 private:
254 QAtomicInt _p;
255 };
256 ThreadData m_data;
257
258 // m_errors should *always* be written before the status is set to Error.
259 // We use the status change as a memory fence around m_errors so that locking
260 // isn't required. Once the status is set to Error (or Complete), m_errors
261 // cannot be changed.
262 QList<QQmlError> m_errors;
263
264 Type m_type;
265
266 QUrl m_url;
267 QUrl m_finalUrl;
268 mutable QString m_urlString;
269 mutable QString m_finalUrlString;
270
271 // List of QQmlDataBlob's that are waiting for me to complete.
272protected:
273 QList<QQmlDataBlob *> m_waitingOnMe;
274private:
275
276 // List of QQmlDataBlob's that I am waiting for to complete.
277 QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
278
279 int m_redirectCount:30;
280 bool m_inCallback:1;
281 bool m_isDone:1;
282};
283
284QT_END_NAMESPACE
285
286#endif // QQMLDATABLOB_P_H
The QQmlDataBlob encapsulates a data request that can be issued to a QQmlTypeLoader.