2e74d6d0a796042ba4afba8a9a0d9735dd95f581
[profile/ivi/qtdeclarative.git] / src / quick / util / qdeclarativefontloader.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativefontloader_p.h"
43
44 #include <qdeclarativecontext.h>
45 #include <qdeclarativeengine.h>
46
47 #include <QStringList>
48 #include <QUrl>
49 #include <QDebug>
50 #include <QNetworkRequest>
51 #include <QNetworkReply>
52 #include <QFontDatabase>
53
54 #include <private/qobject_p.h>
55 #include <private/qdeclarativeengine_p.h>
56 #include <qdeclarativeinfo.h>
57
58 QT_BEGIN_NAMESPACE
59
60 #define FONTLOADER_MAXIMUM_REDIRECT_RECURSION 16
61
62 class QDeclarativeFontObject : public QObject
63 {
64 Q_OBJECT
65
66 public:
67     QDeclarativeFontObject(int _id);
68
69     void download(const QUrl &url, QNetworkAccessManager *manager);
70
71 Q_SIGNALS:
72     void fontDownloaded(const QString&, QDeclarativeFontLoader::Status);
73
74 private Q_SLOTS:
75     void replyFinished();
76
77 public:
78     int id;
79
80 private:
81     QNetworkReply *reply;
82     int redirectCount;
83
84     Q_DISABLE_COPY(QDeclarativeFontObject)
85 };
86
87 QDeclarativeFontObject::QDeclarativeFontObject(int _id = -1)
88     : QObject(0), id(_id), reply(0), redirectCount(0) {}
89
90
91 void QDeclarativeFontObject::download(const QUrl &url, QNetworkAccessManager *manager)
92 {
93     QNetworkRequest req(url);
94     req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
95     reply = manager->get(req);
96     QObject::connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
97 }
98
99 void QDeclarativeFontObject::replyFinished()
100 {
101     if (reply) {
102         redirectCount++;
103         if (redirectCount < FONTLOADER_MAXIMUM_REDIRECT_RECURSION) {
104             QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
105             if (redirect.isValid()) {
106                 QUrl url = reply->url().resolved(redirect.toUrl());
107                 QNetworkAccessManager *manager = reply->manager();
108                 reply->deleteLater();
109                 reply = 0;
110                 download(url, manager);
111                 return;
112             }
113         }
114         redirectCount = 0;
115
116         if (!reply->error()) {
117             id = QFontDatabase::addApplicationFontFromData(reply->readAll());
118             if (id != -1)
119                 emit fontDownloaded(QFontDatabase::applicationFontFamilies(id).at(0), QDeclarativeFontLoader::Ready);
120             else
121                 emit fontDownloaded(QString(), QDeclarativeFontLoader::Error);
122         } else {
123             emit fontDownloaded(QString(), QDeclarativeFontLoader::Error);
124         }
125         reply->deleteLater();
126         reply = 0;
127     }
128 }
129
130
131 class QDeclarativeFontLoaderPrivate : public QObjectPrivate
132 {
133     Q_DECLARE_PUBLIC(QDeclarativeFontLoader)
134
135 public:
136     QDeclarativeFontLoaderPrivate() : status(QDeclarativeFontLoader::Null) {}
137
138     QUrl url;
139     QString name;
140     QDeclarativeFontLoader::Status status;
141     static QHash<QUrl, QDeclarativeFontObject*> fonts;
142 };
143
144 QHash<QUrl, QDeclarativeFontObject*> QDeclarativeFontLoaderPrivate::fonts;
145
146 /*!
147     \qmlclass FontLoader QDeclarativeFontLoader
148     \inqmlmodule QtQuick 2
149   \ingroup qml-utility-elements
150     \brief The FontLoader element allows fonts to be loaded by name or URL.
151
152     The FontLoader element is used to load fonts by name or URL. 
153     
154     The \l status indicates when the font has been loaded, which is useful 
155     for fonts loaded from remote sources.
156
157     For example:
158     \qml
159     import QtQuick 1.0
160
161     Column { 
162         FontLoader { id: fixedFont; name: "Courier" }
163         FontLoader { id: webFont; source: "http://www.mysite.com/myfont.ttf" }
164
165         Text { text: "Fixed-size font"; font.family: fixedFont.name }
166         Text { text: "Fancy font"; font.family: webFont.name }
167     }
168     \endqml
169
170     \sa {declarative/text/fonts}{Fonts example}
171 */
172 QDeclarativeFontLoader::QDeclarativeFontLoader(QObject *parent)
173     : QObject(*(new QDeclarativeFontLoaderPrivate), parent)
174 {
175 }
176
177 QDeclarativeFontLoader::~QDeclarativeFontLoader()
178 {
179 }
180
181 /*!
182     \qmlproperty url QtQuick2::FontLoader::source
183     The url of the font to load.
184 */
185 QUrl QDeclarativeFontLoader::source() const
186 {
187     Q_D(const QDeclarativeFontLoader);
188     return d->url;
189 }
190
191 void QDeclarativeFontLoader::setSource(const QUrl &url)
192 {
193     Q_D(QDeclarativeFontLoader);
194     if (url == d->url)
195         return;
196     d->url = url;
197     emit sourceChanged();
198
199     QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
200     if (!localFile.isEmpty()) {
201         if (!d->fonts.contains(d->url)) {
202             int id = QFontDatabase::addApplicationFont(localFile);
203             if (id != -1) {
204                 updateFontInfo(QFontDatabase::applicationFontFamilies(id).at(0), Ready);
205                 QDeclarativeFontObject *fo = new QDeclarativeFontObject(id);
206                 d->fonts[d->url] = fo;
207             } else {
208                 updateFontInfo(QString(), Error);
209             }
210         } else {
211             updateFontInfo(QFontDatabase::applicationFontFamilies(d->fonts[d->url]->id).at(0), Ready);
212         }
213     } else {
214         if (!d->fonts.contains(d->url)) {
215             QDeclarativeFontObject *fo = new QDeclarativeFontObject;
216             d->fonts[d->url] = fo;
217             fo->download(d->url, qmlEngine(this)->networkAccessManager());
218             d->status = Loading;
219             emit statusChanged();
220             QObject::connect(fo, SIGNAL(fontDownloaded(QString,QDeclarativeFontLoader::Status)),
221                 this, SLOT(updateFontInfo(QString,QDeclarativeFontLoader::Status)));
222         } else {
223             QDeclarativeFontObject *fo = d->fonts[d->url];
224             if (fo->id == -1) {
225                 d->status = Loading;
226                 emit statusChanged();
227                 QObject::connect(fo, SIGNAL(fontDownloaded(QString,QDeclarativeFontLoader::Status)),
228                     this, SLOT(updateFontInfo(QString,QDeclarativeFontLoader::Status)));
229             }
230             else
231                 updateFontInfo(QFontDatabase::applicationFontFamilies(fo->id).at(0), Ready);
232         }
233     }
234 }
235
236 void QDeclarativeFontLoader::updateFontInfo(const QString& name, QDeclarativeFontLoader::Status status)
237 {
238     Q_D(QDeclarativeFontLoader);
239
240     if (name != d->name) {
241         d->name = name;
242         emit nameChanged();
243     }
244     if (status != d->status) {
245         if (status == Error)
246             qmlInfo(this) << "Cannot load font: \"" << d->url.toString() << "\"";
247         d->status = status;
248         emit statusChanged();
249     }
250 }
251
252 /*!
253     \qmlproperty string QtQuick2::FontLoader::name
254
255     This property holds the name of the font family.
256     It is set automatically when a font is loaded using the \c url property.
257
258     Use this to set the \c font.family property of a \c Text item.
259
260     Example:
261     \qml
262     Item {
263         width: 200; height: 50
264
265         FontLoader {
266             id: webFont
267             source: "http://www.mysite.com/myfont.ttf"
268         }
269         Text {
270             text: "Fancy font"
271             font.family: webFont.name
272         }
273     }
274     \endqml
275 */
276 QString QDeclarativeFontLoader::name() const
277 {
278     Q_D(const QDeclarativeFontLoader);
279     return d->name;
280 }
281
282 void QDeclarativeFontLoader::setName(const QString &name)
283 {
284     Q_D(QDeclarativeFontLoader);
285     if (d->name == name)
286         return;
287     d->name = name;
288     emit nameChanged();
289     d->status = Ready;
290     emit statusChanged();
291 }
292
293 /*!
294     \qmlproperty enumeration QtQuick2::FontLoader::status
295
296     This property holds the status of font loading.  It can be one of:
297     \list
298     \o FontLoader.Null - no font has been set
299     \o FontLoader.Ready - the font has been loaded
300     \o FontLoader.Loading - the font is currently being loaded
301     \o FontLoader.Error - an error occurred while loading the font
302     \endlist
303
304     Use this status to provide an update or respond to the status change in some way.
305     For example, you could:
306
307     \list
308     \o Trigger a state change:
309     \qml
310         State { name: 'loaded'; when: loader.status == FontLoader.Ready }
311     \endqml
312
313     \o Implement an \c onStatusChanged signal handler:
314     \qml
315         FontLoader {
316             id: loader
317             onStatusChanged: if (loader.status == FontLoader.Ready) console.log('Loaded')
318         }
319     \endqml
320
321     \o Bind to the status value:
322     \qml
323         Text { text: loader.status == FontLoader.Ready ? 'Loaded' : 'Not loaded' }
324     \endqml
325     \endlist
326 */
327 QDeclarativeFontLoader::Status QDeclarativeFontLoader::status() const
328 {
329     Q_D(const QDeclarativeFontLoader);
330     return d->status;
331 }
332
333 QT_END_NAMESPACE
334
335 #include <qdeclarativefontloader.moc>