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