Update spec to build Qt 5.0
[profile/ivi/qtbase.git] / src / gui / text / qfontdatabase_qpa.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qlibraryinfo.h"
43 #include <QtCore/qsettings.h>
44
45 #include "qfontengine_qpa_p.h"
46 #include "qplatformdefs.h"
47
48 #include <QtGui/private/qguiapplication_p.h>
49 #include <qpa/qplatformfontdatabase.h>
50
51 #include <QtCore/qmath.h>
52
53 QT_BEGIN_NAMESPACE
54
55 Q_GUI_EXPORT  void qt_registerFont(const QString &familyName, const QString &stylename,
56                                    const QString &foundryname, int weight,
57                                    QFont::Style style, int stretch, bool antialiased,
58                                    bool scalable, int pixelSize, bool fixedPitch,
59                                    const QSupportedWritingSystems &writingSystems, void *handle)
60 {
61     QFontDatabasePrivate *d = privateDb();
62 //    qDebug() << "Adding font" << familyName << weight << style << pixelSize << antialiased;
63     QtFontStyle::Key styleKey;
64     styleKey.style = style;
65     styleKey.weight = weight;
66     styleKey.stretch = stretch;
67     QtFontFamily *f = d->family(familyName, true);
68     f->fixedPitch = fixedPitch;
69
70     for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
71         if (writingSystems.supported(QFontDatabase::WritingSystem(i))) {
72             f->writingSystems[i] = QtFontFamily::Supported;
73         } else {
74             f->writingSystems[i] = QtFontFamily::Unsupported;
75         }
76     }
77
78     QtFontFoundry *foundry = f->foundry(foundryname, true);
79     QtFontStyle *fontStyle = foundry->style(styleKey, stylename, true);
80     fontStyle->smoothScalable = scalable;
81     fontStyle->antialiased = antialiased;
82     QtFontSize *size = fontStyle->pixelSize(pixelSize ? pixelSize : SMOOTH_SCALABLE, true);
83     if (size->handle) {
84         QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
85         if (integration)
86             integration->fontDatabase()->releaseHandle(size->handle);
87     }
88     size->handle = handle;
89 }
90
91 Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
92 {
93     if (alias.isEmpty())
94         return;
95
96     QFontDatabasePrivate *d = privateDb();
97     QtFontFamily *f = d->family(familyName, false);
98     if (!f)
99         return;
100
101     if (f->aliases.contains(alias, Qt::CaseInsensitive))
102         return;
103
104     f->aliases.push_back(alias);
105 }
106
107 static QStringList fallbackFamilies(const QString &family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script)
108 {
109     QStringList retList = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script);
110     QFontDatabasePrivate *db = privateDb();
111
112     QStringList::iterator i;
113     for (i = retList.begin(); i != retList.end(); ++i) {
114         bool contains = false;
115         for (int j = 0; j < db->count; j++) {
116             QtFontFamily *qtFamily = db->families[j];
117             if (!(i->compare(qtFamily->name,Qt::CaseInsensitive))) {
118                 contains = true;
119                 break;
120             }
121         }
122         if (!contains) {
123             i = retList.erase(i);
124             i--;
125         }
126     }
127     return retList;
128 }
129
130 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
131
132 static void initializeDb()
133 {
134     QFontDatabasePrivate *db = privateDb();
135
136     // init by asking for the platformfontdb for the first time or after invalidation
137     if (!db->count)
138         QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase();
139
140     if (db->reregisterAppFonts) {
141         for (int i = 0; i < db->applicationFonts.count(); i++) {
142             if (!db->applicationFonts.at(i).families.isEmpty())
143                 registerFont(&db->applicationFonts[i]);
144         }
145         db->reregisterAppFonts = false;
146     }
147 }
148
149 static inline void load(const QString & = QString(), int = -1)
150 {
151     // Only initialize the database if it has been cleared or not initialized yet
152     if (!privateDb()->count)
153         initializeDb();
154 }
155
156 static
157 QFontEngine *loadSingleEngine(int script,
158                               const QFontDef &request,
159                               QtFontFoundry *foundry,
160                               QtFontStyle *style, QtFontSize *size)
161 {
162     Q_UNUSED(foundry);
163
164     Q_ASSERT(size);
165     QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
166     int pixelSize = size->pixelSize;
167     if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE)
168         || pfdb->fontsAlwaysScalable()) {
169         pixelSize = request.pixelSize;
170     }
171
172     QFontDef def = request;
173     def.pixelSize = pixelSize;
174
175     QFontCache::Key key(def,script);
176     QFontEngine *engine = QFontCache::instance()->findEngine(key);
177     if (!engine) {
178         engine = pfdb->fontEngine(def,QUnicodeTables::Script(script),size->handle);
179         if (engine) {
180             QFontCache::Key key(def,script);
181             QFontCache::instance()->instance()->insertEngine(key,engine);
182         }
183     }
184     return engine;
185 }
186
187 static
188 QFontEngine *loadEngine(int script, const QFontDef &request,
189                         QtFontFamily *family, QtFontFoundry *foundry,
190                         QtFontStyle *style, QtFontSize *size)
191 {
192
193     QFontEngine *engine = loadSingleEngine(script, request, foundry, style, size);
194     //make sure that the db has all fallback families
195     if (engine && engine->type() != QFontEngine::Multi
196         && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol ) {
197
198         if (family && !family->askedForFallback) {
199             QFont::Style fontStyle = QFont::Style(style->key.style);
200             QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint);
201             if (styleHint == QFont::AnyStyle && request.fixedPitch)
202                 styleHint = QFont::TypeWriter;
203             family->fallbackFamilies = fallbackFamilies(family->name,fontStyle,styleHint,QUnicodeTables::Script(script));
204
205             family->askedForFallback = true;
206         }
207
208         QStringList fallbacks = privateDb()->fallbackFamilies;
209         if (family && !family->fallbackFamilies.isEmpty())
210             fallbacks = family->fallbackFamilies;
211
212         QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
213         QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QUnicodeTables::Script(script));
214         pfMultiEngine->setFallbackFamiliesList(fallbacks);
215         engine = pfMultiEngine;
216
217         // Cache Multi font engine as well in case we got the FT single
218         // font engine when we are actually looking for a Multi one
219         QFontCache::Key key(request, script, 1);
220         QFontCache::instance()->instance()->insertEngine(key, engine);
221     }
222
223     return engine;
224 }
225
226 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
227 {
228     QFontDatabasePrivate *db = privateDb();
229
230     fnt->families = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data,fnt->fileName);
231
232     db->reregisterAppFonts = true;
233 }
234
235 bool QFontDatabase::removeApplicationFont(int handle)
236 {
237     QMutexLocker locker(fontDatabaseMutex());
238
239     QFontDatabasePrivate *db = privateDb();
240     if (handle < 0 || handle >= db->applicationFonts.count())
241         return false;
242
243     db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
244
245     db->reregisterAppFonts = true;
246     db->invalidate();
247     return true;
248 }
249
250 bool QFontDatabase::removeAllApplicationFonts()
251 {
252     QMutexLocker locker(fontDatabaseMutex());
253
254     QFontDatabasePrivate *db = privateDb();
255     if (db->applicationFonts.isEmpty())
256         return false;
257
258     db->applicationFonts.clear();
259     db->invalidate();
260     return true;
261 }
262
263 bool QFontDatabase::supportsThreadedFontRendering()
264 {
265     return true;
266 }
267
268 /*!
269     \internal
270 */
271 QFontEngine *
272 QFontDatabase::findFont(int script, const QFontPrivate *fp,
273                         const QFontDef &request, bool multi)
274 {
275     QMutexLocker locker(fontDatabaseMutex());
276
277     const int force_encoding_id = -1;
278
279     if (!privateDb()->count)
280         initializeDb();
281
282     QFontEngine *engine;
283     QFontCache::Key key(request, script, multi ? 1 : 0);
284     engine = QFontCache::instance()->findEngine(key);
285     if (engine) {
286         FM_DEBUG("Cache hit level 1");
287         return engine;
288     }
289
290     QString family_name, foundry_name;
291
292     parseFontName(request.family, foundry_name, family_name);
293
294     if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
295         engine =new QTestFontEngine(request.pixelSize);
296         engine->fontDef = request;
297     }
298
299     QtFontDesc desc;
300     match(script, request, family_name, foundry_name, force_encoding_id, &desc);
301     if (desc.family != 0 && desc.foundry != 0 && desc.style != 0) {
302         engine = loadEngine(script, request, desc.family, desc.foundry, desc.style, desc.size);
303     } else {
304         FM_DEBUG("  NO MATCH FOUND\n");
305     }
306
307     if (engine && engine->type() != QFontEngine::TestFontEngine) {
308         initFontDef(desc, request, &engine->fontDef, engine->type() == QFontEngine::Multi);
309
310         if (fp) {
311             QFontDef def = request;
312             if (def.family.isEmpty()) {
313                 def.family = fp->request.family;
314                 def.family = def.family.left(def.family.indexOf(QLatin1Char(',')));
315             }
316         }
317     }
318
319     if (!engine) {
320         if (!request.family.isEmpty()) {
321             QStringList fallbacks = request.fallBackFamilies
322                                   + fallbackFamilies(request.family,
323                                                      QFont::Style(request.style),
324                                                      QFont::StyleHint(request.styleHint),
325                                                      QUnicodeTables::Script(script));
326
327             for (int i = 0; !engine && i < fallbacks.size(); i++) {
328                 QFontDef def = request;
329                 def.family = fallbacks.at(i);
330                 QFontCache::Key key(def, script, multi ? 1 : 0);
331                 engine = QFontCache::instance()->findEngine(key);
332                 if (!engine) {
333                     QtFontDesc desc;
334                     match(script, def, def.family, QLatin1String(""), 0, &desc);
335                     if (desc.family == 0 && desc.foundry == 0 && desc.style == 0) {
336                         continue;
337                     }
338                     engine = loadEngine(script, def, desc.family, desc.foundry, desc.style, desc.size);
339                     if (engine) {
340                         initFontDef(desc, def, &engine->fontDef, engine->type() == QFontEngine::Multi);
341                     }
342                 }
343             }
344         }
345
346         if (!engine)
347             engine = new QFontEngineBox(request.pixelSize);
348
349         FM_DEBUG("returning box engine");
350     }
351
352     if (fp && fp->dpi > 0) {
353         engine->fontDef.pointSize = qreal(double((engine->fontDef.pixelSize * 72) / fp->dpi));
354     } else {
355         engine->fontDef.pointSize = request.pointSize;
356     }
357
358     return engine;
359 }
360
361 void QFontDatabase::load(const QFontPrivate *d, int script)
362 {
363     QFontDef req = d->request;
364
365     if (req.pixelSize == -1) {
366         req.pixelSize = floor(((req.pointSize * d->dpi) / 72) * 100 + 0.5) / 100;
367         req.pixelSize = qRound(req.pixelSize);
368     }
369     if (req.pointSize < 0)
370         req.pointSize = req.pixelSize*72.0/d->dpi;
371     if (req.weight == 0)
372         req.weight = QFont::Normal;
373     if (req.stretch == 0)
374         req.stretch = 100;
375
376     // Until we specifically asked not to, try looking for Multi font engine
377     // first, the last '1' indicates that we want Multi font engine instead
378     // of single ones
379     bool multi = !(req.styleStrategy & QFont::NoFontMerging);
380     QFontCache::Key key(req, script, multi ? 1 : 0);
381
382     if (!d->engineData)
383         getEngineData(d, req);
384
385     // the cached engineData could have already loaded the engine we want
386     if (d->engineData->engines[script])
387         return;
388
389     QFontEngine *fe = QFontCache::instance()->findEngine(key);
390
391     // list of families to try
392     QStringList family_list;
393
394     if (!req.family.isEmpty()) {
395         QStringList familiesForRequest = familyList(req);
396
397         // Add primary selection
398         family_list << familiesForRequest.takeFirst();
399
400         // Fallbacks requested in font request
401         req.fallBackFamilies = familiesForRequest;
402
403         // add the default family
404         QString defaultFamily = QGuiApplication::font().family();
405         if (! family_list.contains(defaultFamily))
406             family_list << defaultFamily;
407
408     }
409
410     // null family means find the first font matching the specified script
411     family_list << QString();
412
413     QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
414     for (; !fe && it != end; ++it) {
415         req.family = *it;
416
417         fe = QFontDatabase::findFont(script, d, req, multi);
418         if (fe && (fe->type()==QFontEngine::Box) && !req.family.isEmpty()) {
419             if (fe->ref.load() == 0)
420                 delete fe;
421
422             fe = 0;
423         }
424
425         // No need to check requested fallback families again
426         req.fallBackFamilies.clear();
427     }
428
429     if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
430         for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
431             if (!d->engineData->engines[i]) {
432                 d->engineData->engines[i] = fe;
433                 fe->ref.ref();
434             }
435         }
436     } else {
437         d->engineData->engines[script] = fe;
438         fe->ref.ref();
439     }
440 }
441
442 QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
443 {
444     return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family);
445 }
446
447 QT_END_NAMESPACE