d89e64c9553f6d05db9f88c9c58827717f8a7bc4
[profile/ivi/qtdeclarative.git] / src / qtquick1 / 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 "QtQuick1/private/qdeclarativefontloader_p.h"
43
44 #include <QtDeclarative/qdeclarativecontext.h>
45 #include <QtDeclarative/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 <QtDeclarative/private/qdeclarativeengine_p.h>
56 #include <QtDeclarative/qdeclarativeinfo.h>
57
58 QT_BEGIN_NAMESPACE
59
60
61
62 #define FONTLOADER_MAXIMUM_REDIRECT_RECURSION 16
63
64 class QDeclarative1FontObject : public QObject
65 {
66 Q_OBJECT
67
68 public:
69     QDeclarative1FontObject(int _id);
70
71     void download(const QUrl &url, QNetworkAccessManager *manager);
72
73 Q_SIGNALS:
74     void fontDownloaded(const QString&, QDeclarative1FontLoader::Status);
75
76 private Q_SLOTS:
77     void replyFinished();
78
79 public:
80     int id;
81
82 private:
83     QNetworkReply *reply;
84     int redirectCount;
85
86     Q_DISABLE_COPY(QDeclarative1FontObject)
87 };
88
89 QDeclarative1FontObject::QDeclarative1FontObject(int _id = -1)
90     : QObject(0), id(_id), reply(0), redirectCount(0) {}
91
92
93 void QDeclarative1FontObject::download(const QUrl &url, QNetworkAccessManager *manager)
94 {
95     QNetworkRequest req(url);
96     req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
97     reply = manager->get(req);
98     QObject::connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
99 }
100
101 void QDeclarative1FontObject::replyFinished()
102 {
103     if (reply) {
104         redirectCount++;
105         if (redirectCount < FONTLOADER_MAXIMUM_REDIRECT_RECURSION) {
106             QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
107             if (redirect.isValid()) {
108                 QUrl url = reply->url().resolved(redirect.toUrl());
109                 QNetworkAccessManager *manager = reply->manager();
110                 reply->deleteLater();
111                 reply = 0;
112                 download(url, manager);
113                 return;
114             }
115         }
116         redirectCount = 0;
117
118         if (!reply->error()) {
119             id = QFontDatabase::addApplicationFontFromData(reply->readAll());
120             if (id != -1)
121                 emit fontDownloaded(QFontDatabase::applicationFontFamilies(id).at(0), QDeclarative1FontLoader::Ready);
122             else
123                 emit fontDownloaded(QString(), QDeclarative1FontLoader::Error);
124         } else {
125             emit fontDownloaded(QString(), QDeclarative1FontLoader::Error);
126         }
127         reply->deleteLater();
128         reply = 0;
129     }
130 }
131
132
133 class QDeclarative1FontLoaderPrivate : public QObjectPrivate
134 {
135     Q_DECLARE_PUBLIC(QDeclarative1FontLoader)
136
137 public:
138     QDeclarative1FontLoaderPrivate() : status(QDeclarative1FontLoader::Null) {}
139
140     QUrl url;
141     QString name;
142     QDeclarative1FontLoader::Status status;
143     static QHash<QUrl, QDeclarative1FontObject*> fonts;
144 };
145
146 QHash<QUrl, QDeclarative1FontObject*> QDeclarative1FontLoaderPrivate::fonts;
147
148 /*!
149     \qmlclass FontLoader QDeclarative1FontLoader
150     \inqmlmodule QtQuick 1
151   \ingroup qml-utility-elements
152     \since QtQuick 1.0
153     \brief The FontLoader element allows fonts to be loaded by name or URL.
154
155     The FontLoader element is used to load fonts by name or URL. 
156     
157     The \l status indicates when the font has been loaded, which is useful 
158     for fonts loaded from remote sources.
159
160     For example:
161     \qml
162     import QtQuick 1.0
163
164     Column { 
165         FontLoader { id: fixedFont; name: "Courier" }
166         FontLoader { id: webFont; source: "http://www.mysite.com/myfont.ttf" }
167
168         Text { text: "Fixed-size font"; font.family: fixedFont.name }
169         Text { text: "Fancy font"; font.family: webFont.name }
170     }
171     \endqml
172
173     \sa {declarative/text/fonts}{Fonts example}
174 */
175 QDeclarative1FontLoader::QDeclarative1FontLoader(QObject *parent)
176     : QObject(*(new QDeclarative1FontLoaderPrivate), parent)
177 {
178 }
179
180 QDeclarative1FontLoader::~QDeclarative1FontLoader()
181 {
182 }
183
184 /*!
185     \qmlproperty url QtQuick1::FontLoader::source
186     The url of the font to load.
187 */
188 QUrl QDeclarative1FontLoader::source() const
189 {
190     Q_D(const QDeclarative1FontLoader);
191     return d->url;
192 }
193
194 void QDeclarative1FontLoader::setSource(const QUrl &url)
195 {
196     Q_D(QDeclarative1FontLoader);
197     if (url == d->url)
198         return;
199     d->url = qmlContext(this)->resolvedUrl(url);
200     emit sourceChanged();
201
202 #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
203     QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
204     if (!localFile.isEmpty()) {
205         if (!d->fonts.contains(d->url)) {
206             int id = QFontDatabase::addApplicationFont(localFile);
207             if (id != -1) {
208                 updateFontInfo(QFontDatabase::applicationFontFamilies(id).at(0), Ready);
209                 QDeclarative1FontObject *fo = new QDeclarative1FontObject(id);
210                 d->fonts[d->url] = fo;
211             } else {
212                 updateFontInfo(QString(), Error);
213             }
214         } else {
215             updateFontInfo(QFontDatabase::applicationFontFamilies(d->fonts[d->url]->id).at(0), Ready);
216         }
217     } else
218 #endif
219     {
220         if (!d->fonts.contains(d->url)) {
221             QDeclarative1FontObject *fo = new QDeclarative1FontObject;
222             d->fonts[d->url] = fo;
223             fo->download(d->url, qmlEngine(this)->networkAccessManager());
224             d->status = Loading;
225             emit statusChanged();
226             QObject::connect(fo, SIGNAL(fontDownloaded(QString,QDeclarative1FontLoader::Status)),
227                 this, SLOT(updateFontInfo(QString,QDeclarative1FontLoader::Status)));
228         } else {
229             QDeclarative1FontObject *fo = d->fonts[d->url];
230             if (fo->id == -1) {
231                 d->status = Loading;
232                 emit statusChanged();
233                 QObject::connect(fo, SIGNAL(fontDownloaded(QString,QDeclarative1FontLoader::Status)),
234                     this, SLOT(updateFontInfo(QString,QDeclarative1FontLoader::Status)));
235             }
236             else
237                 updateFontInfo(QFontDatabase::applicationFontFamilies(fo->id).at(0), Ready);
238         }
239     }
240 }
241
242 void QDeclarative1FontLoader::updateFontInfo(const QString& name, QDeclarative1FontLoader::Status status)
243 {
244     Q_D(QDeclarative1FontLoader);
245
246     if (name != d->name) {
247         d->name = name;
248         emit nameChanged();
249     }
250     if (status != d->status) {
251         if (status == Error)
252             qmlInfo(this) << "Cannot load font: \"" << d->url.toString() << "\"";
253         d->status = status;
254         emit statusChanged();
255     }
256 }
257
258 /*!
259     \qmlproperty string QtQuick1::FontLoader::name
260
261     This property holds the name of the font family.
262     It is set automatically when a font is loaded using the \c url property.
263
264     Use this to set the \c font.family property of a \c Text item.
265
266     Example:
267     \qml
268     Item {
269         width: 200; height: 50
270
271         FontLoader {
272             id: webFont
273             source: "http://www.mysite.com/myfont.ttf"
274         }
275         Text {
276             text: "Fancy font"
277             font.family: webFont.name
278         }
279     }
280     \endqml
281 */
282 QString QDeclarative1FontLoader::name() const
283 {
284     Q_D(const QDeclarative1FontLoader);
285     return d->name;
286 }
287
288 void QDeclarative1FontLoader::setName(const QString &name)
289 {
290     Q_D(QDeclarative1FontLoader);
291     if (d->name == name)
292         return;
293     d->name = name;
294     emit nameChanged();
295     d->status = Ready;
296     emit statusChanged();
297 }
298
299 /*!
300     \qmlproperty enumeration QtQuick1::FontLoader::status
301
302     This property holds the status of font loading.  It can be one of:
303     \list
304     \o FontLoader.Null - no font has been set
305     \o FontLoader.Ready - the font has been loaded
306     \o FontLoader.Loading - the font is currently being loaded
307     \o FontLoader.Error - an error occurred while loading the font
308     \endlist
309
310     Use this status to provide an update or respond to the status change in some way.
311     For example, you could:
312
313     \list
314     \o Trigger a state change:
315     \qml
316         State { name: 'loaded'; when: loader.status == FontLoader.Ready }
317     \endqml
318
319     \o Implement an \c onStatusChanged signal handler:
320     \qml
321         FontLoader {
322             id: loader
323             onStatusChanged: if (loader.status == FontLoader.Ready) console.log('Loaded')
324         }
325     \endqml
326
327     \o Bind to the status value:
328     \qml
329         Text { text: loader.status == FontLoader.Ready ? 'Loaded' : 'Not loaded' }
330     \endqml
331     \endlist
332 */
333 QDeclarative1FontLoader::Status QDeclarative1FontLoader::status() const
334 {
335     Q_D(const QDeclarative1FontLoader);
336     return d->status;
337 }
338
339
340
341 QT_END_NAMESPACE
342
343 #include <qdeclarativefontloader.moc>