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
qquickfontloader.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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
5
6#include <qqmlcontext.h>
7#include <qqmlengine.h>
8
9#include <QStringList>
10#include <QUrl>
11#include <QDebug>
12
13#include <QFontDatabase>
14
15#include <private/qobject_p.h>
16#include <qqmlinfo.h>
17#include <qqmlfile.h>
18
19#if QT_CONFIG(qml_network)
20#include <QNetworkRequest>
21#include <QNetworkReply>
22#endif
23
24#include <QtCore/QCoreApplication>
25#include <QtCore/private/qduplicatetracker_p.h>
26
27#include <QtGui/private/qfontdatabase_p.h>
28
30
32{
34
35public:
36 explicit QQuickFontObject(int _id = -1);
37
38#if QT_CONFIG(qml_network)
40
42 void fontDownloaded(int id);
43
44private:
45 QNetworkReply *reply = nullptr;
46
47private Q_SLOTS:
48 void replyFinished();
49#endif // qml_network
50
51public:
52 int id;
53
55};
56
57QQuickFontObject::QQuickFontObject(int _id)
58 : QObject(nullptr), id(_id)
59{
60}
61
62#if QT_CONFIG(qml_network)
63void QQuickFontObject::download(const QUrl &url, QNetworkAccessManager *manager)
64{
65 QNetworkRequest req(url);
66 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
67 reply = manager->get(req);
68 QObject::connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
69}
70
71void QQuickFontObject::replyFinished()
72{
73 if (reply) {
74 if (!reply->error()) {
75 id = QFontDatabase::addApplicationFontFromData(reply->readAll());
76 emit fontDownloaded(id);
77 } else {
78 qWarning("%s: Unable to load font '%s': %s", Q_FUNC_INFO,
79 qPrintable(reply->url().toString()), qPrintable(reply->errorString()));
80 emit fontDownloaded(-1);
81 }
82 reply->deleteLater();
83 reply = nullptr;
84 }
85}
86#endif // qml_network
87
89{
90 Q_DECLARE_PUBLIC(QQuickFontLoader)
91
92public:
94
98};
99
102{
103 qAddPostRoutine(q_QFontLoaderFontsStaticReset);
104}
106{
107public:
109 {
110 qAddPostRoutine(q_QFontLoaderFontsStaticReset);
111 qAddPreRoutine(q_QFontLoaderFontsAddReset);
112 }
113
115 {
116 qRemovePostRoutine(q_QFontLoaderFontsStaticReset);
117 reset();
118 }
119
120
121 void reset()
122 {
123 QDuplicateTracker<QQuickFontObject *, 256> deleted(map.size());
124 for (QQuickFontObject *fo : std::as_const(map)) {
125 if (!deleted.hasSeen(fo))
126 delete fo;
127 }
128 map.clear();
129 }
130
132};
134
136{
137 fontLoaderFonts()->reset();
138}
139
140/*!
141 \qmltype FontLoader
142 \nativetype QQuickFontLoader
143 \inqmlmodule QtQuick
144 \ingroup qtquick-text-utility
145 \brief Allows fonts to be loaded by URL.
146
147 The FontLoader type is used to load fonts by URL.
148
149 The \l status indicates when the font has been loaded, which is useful
150 for fonts loaded from remote sources.
151
152 For example:
153 \qml
154 import QtQuick 2.0
155
156 Column {
157 FontLoader { id: webFont; source: "http://www.mysite.com/myfont.ttf" }
158
159 Text { text: "Fancy font"; font: webFont.font }
160 }
161 \endqml
162
163 \sa {Qt Quick Examples - Text#Fonts}{Qt Quick Examples - Text Fonts}
164*/
165QQuickFontLoader::QQuickFontLoader(QObject *parent)
166 : QObject(*(new QQuickFontLoaderPrivate), parent)
167{
168 connect(this, &QQuickFontLoader::fontChanged, this, &QQuickFontLoader::nameChanged);
169}
170
171/*!
172 \qmlproperty url QtQuick::FontLoader::source
173 The URL of the font to load.
174*/
175QUrl QQuickFontLoader::source() const
176{
177 Q_D(const QQuickFontLoader);
178 return d->url;
179}
180
181void QQuickFontLoader::setSource(const QUrl &url)
182{
183 Q_D(QQuickFontLoader);
184 if (url == d->url)
185 return;
186 d->url = url;
187 emit sourceChanged();
188
189 auto &map = fontLoaderFonts()->map;
190
191 const QQmlContext *context = qmlContext(this);
192 const QUrl &resolvedUrl = context ? context->resolvedUrl(d->url) : d->url;
193 const auto mapEntry = map.constFind(resolvedUrl);
194 const auto mapEnd = map.constEnd();
195
196 const QString localFile = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
197 if (!localFile.isEmpty()) {
198 if (mapEntry == mapEnd) {
199 int id = QFontDatabase::addApplicationFont(localFile);
200 updateFontInfo(id);
201 if (id != -1) {
202 QQuickFontObject *fo = new QQuickFontObject(id);
203 map[resolvedUrl] = fo;
204 }
205 } else {
206 QQuickFontObject *fo = *mapEntry;
207 updateFontInfo(fo->id);
208 }
209 } else if (mapEntry == mapEnd) {
210 Q_ASSERT(context);
211#if QT_CONFIG(qml_network)
212 QQuickFontObject *fo = new QQuickFontObject;
213 map[resolvedUrl] = fo;
214 fo->download(resolvedUrl, context->engine()->networkAccessManager());
215 d->status = Loading;
216 emit statusChanged();
217 QObject::connect(fo, SIGNAL(fontDownloaded(int)),
218 this, SLOT(updateFontInfo(int)));
219#else
220// Silently fail if compiled with no_network
221#endif
222 } else {
223 QQuickFontObject *fo = *mapEntry;
224 if (fo->id == -1) {
225#if QT_CONFIG(qml_network)
226 d->status = Loading;
227 emit statusChanged();
228 QObject::connect(fo, SIGNAL(fontDownloaded(int)),
229 this, SLOT(updateFontInfo(int)));
230#else
231// Silently fail if compiled with no_network
232#endif
233 } else {
234 updateFontInfo(fo->id);
235 }
236 }
237}
238
239void QQuickFontLoader::updateFontInfo(int id)
240{
241 Q_D(QQuickFontLoader);
242
243 QFont font;
244
245 QQuickFontLoader::Status status = Error;
246 if (id >= 0) {
247 QFontDatabasePrivate *p = QFontDatabasePrivate::instance();
248 if (id < p->applicationFonts.size()) {
249 const QFontDatabasePrivate::ApplicationFont &applicationFont = p->applicationFonts.at(id);
250
251 if (!applicationFont.properties.isEmpty()) {
252 const QFontDatabasePrivate::ApplicationFont::Properties &properties = applicationFont.properties.at(0);
253 font.setFamily(properties.familyName);
254 font.setStyleName(properties.styleName);
255 font.setWeight(QFont::Weight(properties.weight));
256 font.setStyle(properties.style);
257 font.setStretch(properties.stretch);
258 }
259 }
260
261 status = Ready;
262 }
263
264 if (font != d->font) {
265 d->font = font;
266 emit fontChanged();
267 }
268
269 if (status != d->status) {
270 if (status == Error) {
271 const QQmlContext *context = qmlContext(this);
272 qmlWarning(this) << "Cannot load font: \""
273 << (context ? context->resolvedUrl(d->url) : d->url).toString() << '"';
274 }
275 d->status = status;
276 emit statusChanged();
277 }
278}
279
280/*!
281 \qmlproperty font QtQuick::FontLoader::font
282 \since 6.0
283
284 This property holds a default query for the loaded font.
285
286 You can use this to select the font if other properties than just the
287 family name are needed to disambiguate. You can either specify the
288 font using individual properties:
289
290 \qml
291 Item {
292 width: 200; height: 50
293
294 FontLoader {
295 id: webFont
296 source: "http://www.mysite.com/myfont.ttf"
297 }
298 Text {
299 text: "Fancy font"
300 font.family: webFont.font.family
301 font.weight: webFont.font.weight
302 font.styleName: webFont.font.styleName
303 font.pixelSize: 24
304 }
305 }
306 \endqml
307
308 Or you can set the full font query directly:
309
310 \qml
311 Item {
312 width: 200; height: 50
313
314 FontLoader {
315 id: webFont
316 source: "http://www.mysite.com/myfont.ttf"
317 }
318 Text {
319 text: "Fancy font"
320 font: webFont.font
321 }
322 }
323 \endqml
324
325 In this case, the default font query will be used with no modifications
326 (so font size, for instance, will be the system default).
327*/
328QFont QQuickFontLoader::font() const
329{
330 Q_D(const QQuickFontLoader);
331 return d->font;
332}
333
334/*!
335 \qmlproperty string QtQuick::FontLoader::name
336 \readonly
337
338 This property holds the name of the font family.
339 It is set automatically when a font is loaded using the \l source property.
340
341 This is equivalent to the family property of the FontLoader's \l font property.
342
343 Use this to set the \c font.family property of a \c Text item.
344
345 Example:
346 \qml
347 Item {
348 width: 200; height: 50
349
350 FontLoader {
351 id: webFont
352 source: "http://www.mysite.com/myfont.ttf"
353 }
354 Text {
355 text: "Fancy font"
356 font.family: webFont.name
357 }
358 }
359 \endqml
360*/
361QString QQuickFontLoader::name() const
362{
363 Q_D(const QQuickFontLoader);
364 return d->font.resolveMask() == 0 ? QString() : d->font.family();
365}
366
367/*!
368 \qmlproperty enumeration QtQuick::FontLoader::status
369
370 This property holds the status of font loading. It can be one of:
371
372 \value FontLoader.Null no font has been set
373 \value FontLoader.Ready the font has been loaded
374 \value FontLoader.Loading the font is currently being loaded
375 \value FontLoader.Error an error occurred while loading the font
376
377 Use this status to provide an update or respond to the status change in some way.
378 For example, you could:
379
380 \list
381 \li Trigger a state change:
382 \qml
383 State { name: 'loaded'; when: loader.status == FontLoader.Ready }
384 \endqml
385
386 \li Implement an \c onStatusChanged signal handler:
387 \qml
388 FontLoader {
389 id: loader
390 onStatusChanged: if (loader.status == FontLoader.Ready) console.log('Loaded')
391 }
392 \endqml
393
394 \li Bind to the status value:
395 \qml
396 Text { text: loader.status == FontLoader.Ready ? 'Loaded' : 'Not loaded' }
397 \endqml
398 \endlist
399*/
400QQuickFontLoader::Status QQuickFontLoader::status() const
401{
402 Q_D(const QQuickFontLoader);
403 return d->status;
404}
405
406QT_END_NAMESPACE
407
408#include <qquickfontloader.moc>
409
410#include "moc_qquickfontloader_p.cpp"
QHash< QUrl, QQuickFontObject * > map
Combined button and popup list for selecting options.
static void q_QFontLoaderFontsAddReset()
static void q_QFontLoaderFontsStaticReset()
Q_GLOBAL_STATIC(QFontLoaderFonts, fontLoaderFonts)