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