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// Qt-Security score:significant
4
5#ifndef QQMLDATABLOB_P_H
6#define QQMLDATABLOB_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <private/qqmlrefcount_p.h>
20#include <private/qqmljsdiagnosticmessage_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_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 virtual ~QQmlDataBlob();
60
61 void startLoading();
62
63 QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
64 void resetTypeLoader() { m_typeLoader = nullptr; }
65
66 Type type() const;
67
68 Status status() const;
69 bool isNull() const;
70 bool isLoading() const;
71 bool isWaiting() const;
72 bool isComplete() const;
73 bool isError() const;
74 bool isCompleteOrError() const;
75
76 bool isAsync() const;
77 qreal progress() const;
78
79 QUrl url() const;
80 QString urlString() const;
81 QUrl finalUrl() const;
82 QString finalUrlString() const;
83
84 QList<QQmlError> errors() const;
85
86 class SourceCodeData {
87 public:
88 QString readAll(QString *error) const;
89 QDateTime sourceTimeStamp() const;
90 QByteArray checksum() const;
91 bool exists() const;
92 bool isEmpty() const;
93 bool isCacheable() const { return !hasStaticData; }
94 bool isValid() const
95 {
96 return hasInlineSourceCode || !fileInfo.filePath().isEmpty();
97 }
98
99 private:
100 friend class QQmlDataBlob;
101 friend class QQmlTypeLoader;
102 QString inlineSourceCode;
103 QFileInfo fileInfo;
104 bool hasInlineSourceCode = false;
105 bool hasStaticData = false;
106 };
107
108 template<typename Loader = QQmlTypeLoader>
109 void assertTypeLoaderThreadIfRunning() const
110 {
111 const Loader *loader = m_typeLoader;
112 Q_ASSERT(!loader || !loader->thread() || loader->thread()->isThisThread());
113 }
114
115 template<typename Loader = QQmlTypeLoader>
116 void assertTypeLoaderThread() const
117 {
118 const Loader *loader = m_typeLoader;
119 Q_ASSERT(loader && loader->thread() && loader->thread()->isThisThread());
120 }
121
122 template<typename Loader = QQmlTypeLoader>
123 void assertEngineThreadIfRunning() const
124 {
125 const Loader *loader = m_typeLoader;
126 Q_ASSERT(!loader || !loader->thread() || loader->thread()->isParentThread());
127 }
128
129 template<typename Loader = QQmlTypeLoader>
130 void assertEngineThread() const
131 {
132 const Loader *loader = m_typeLoader;
133 Q_ASSERT(loader && loader->thread() && loader->thread()->isParentThread());
134 }
135
136protected:
137 // Can be called from within callbacks
138 void setError(const QQmlError &);
139 void setError(const QList<QQmlError> &errors);
140 void setError(const QQmlJS::DiagnosticMessage &error);
141 void setError(const QString &description);
142 void addDependency(const QQmlDataBlob::Ptr &);
143
144 // Callbacks made in load thread
145 virtual void dataReceived(const SourceCodeData &) = 0;
146 virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) = 0;
147 virtual void done();
148#if QT_CONFIG(qml_network)
149 virtual void networkError(QNetworkReply::NetworkError);
150#endif
151 virtual void dependencyError(const QQmlDataBlob::Ptr &);
152 virtual void dependencyComplete(const QQmlDataBlob::Ptr &);
153 virtual void allDependenciesDone();
154
155 // Callbacks made in main thread
156 virtual void downloadProgressChanged(qreal);
157 virtual void completed();
158
159protected:
160 // Manager that is currently fetching data for me
161 QQmlTypeLoader *m_typeLoader;
162
163private:
164 friend class QQmlTypeLoader;
165 friend class QQmlTypeLoaderThread;
166
167 void tryDone();
168 void cancelAllWaitingFor();
169 void notifyAllWaitingOnMe();
170 void notifyComplete(const QQmlDataBlob::Ptr &);
171
172 bool setStatus(Status status);
173 bool setIsAsync(bool async) { return m_data.setIsAsync(async); }
174 bool setProgress(qreal progress) { return m_data.setProgress(progress); }
175
176 struct ThreadData {
177 public:
178 friend bool QQmlDataBlob::setStatus(Status);
179 friend bool QQmlDataBlob::setIsAsync(bool);
180 friend bool QQmlDataBlob::setProgress(qreal);
181
182 inline ThreadData()
183 : _p(0)
184 {
185 }
186
187 inline QQmlDataBlob::Status status() const
188 {
189 return QQmlDataBlob::Status((_p.loadAcquire() & StatusMask) >> StatusShift);
190 }
191
192 inline bool isAsync() const
193 {
194 return _p.loadAcquire() & AsyncMask;
195 }
196
197 inline qreal progress() const
198 {
199 return quint8((_p.loadAcquire() & ProgressMask) >> ProgressShift) / float(0xFF);
200 }
201
202 private:
203 enum {
204 StatusMask = 0x0000FFFF,
205 StatusShift = 0,
206 ProgressMask = 0x00FF0000,
207 ProgressShift = 16,
208 AsyncMask = 0x80000000,
209 NoMask = 0
210 };
211
212
213 inline bool setStatus(QQmlDataBlob::Status status)
214 {
215 while (true) {
216 int d = _p.loadAcquire();
217 int nd = (d & ~StatusMask) | ((status << StatusShift) & StatusMask);
218 if (d == nd)
219 return false;
220 if (_p.testAndSetRelease(d, nd))
221 return true;
222 }
223
224 Q_UNREACHABLE_RETURN(false);
225 }
226
227 inline bool setIsAsync(bool v)
228 {
229 while (true) {
230 int d = _p.loadAcquire();
231 int nd = (d & ~AsyncMask) | (v ? AsyncMask : NoMask);
232 if (d == nd)
233 return false;
234 if (_p.testAndSetRelease(d, nd))
235 return true;
236 }
237
238 Q_UNREACHABLE_RETURN(false);
239 }
240
241 inline bool setProgress(qreal progress)
242 {
243 quint8 v = 0xFF * progress;
244 while (true) {
245 int d = _p.loadAcquire();
246 int nd = (d & ~ProgressMask) | ((v << ProgressShift) & ProgressMask);
247 if (d == nd)
248 return false;
249 if (_p.testAndSetRelease(d, nd))
250 return true;
251 }
252 Q_UNREACHABLE_RETURN(false);
253 }
254
255 private:
256 QAtomicInt _p;
257 };
258 ThreadData m_data;
259
260 // m_errors should *always* be written before the status is set to Error.
261 // We use the status change as a memory fence around m_errors so that locking
262 // isn't required. Once the status is set to Error (or Complete), m_errors
263 // cannot be changed.
264 QList<QQmlError> m_errors;
265
266 Type m_type;
267
268 QUrl m_url;
269 QUrl m_finalUrl;
270 mutable QString m_urlString;
271 mutable QString m_finalUrlString;
272
273 // List of QQmlDataBlob's that are waiting for me to complete.
274protected:
275 QList<QQmlDataBlob *> m_waitingOnMe;
276private:
277
278 // List of QQmlDataBlob's that I am waiting for to complete.
279 QList<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
280
281 int m_redirectCount:30;
282 bool m_inCallback:1;
283 bool m_isDone:1;
284};
285
286QT_END_NAMESPACE
287
288#endif // QQMLDATABLOB_P_H
The QQmlDataBlob encapsulates a data request that can be issued to a QQmlTypeLoader.