1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qlibraryinfo.h"
43 #include <QtCore/qsettings.h>
45 #include "qfontengine_qpa_p.h"
46 #include "qplatformdefs.h"
48 #include <QtGui/private/qguiapplication_p.h>
49 #include <qpa/qplatformfontdatabase.h>
51 #include <QtCore/qmath.h>
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)
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;
70 for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
71 if (writingSystems.supported(QFontDatabase::WritingSystem(i))) {
72 f->writingSystems[i] = QtFontFamily::Supported;
74 f->writingSystems[i] = QtFontFamily::Unsupported;
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);
84 QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
86 integration->fontDatabase()->releaseHandle(size->handle);
88 size->handle = handle;
91 Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
96 QFontDatabasePrivate *d = privateDb();
97 QtFontFamily *f = d->family(familyName, false);
101 if (f->aliases.contains(alias, Qt::CaseInsensitive))
104 f->aliases.push_back(alias);
107 static QStringList fallbackFamilies(const QString &family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script)
109 QStringList retList = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script);
110 QFontDatabasePrivate *db = privateDb();
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))) {
123 i = retList.erase(i);
130 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
132 static void initializeDb()
134 QFontDatabasePrivate *db = privateDb();
136 // init by asking for the platformfontdb for the first time or after invalidation
138 QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase();
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]);
145 db->reregisterAppFonts = false;
149 static inline void load(const QString & = QString(), int = -1)
151 // Only initialize the database if it has been cleared or not initialized yet
152 if (!privateDb()->count)
157 QFontEngine *loadSingleEngine(int script,
158 const QFontDef &request,
159 QtFontFoundry *foundry,
160 QtFontStyle *style, QtFontSize *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;
172 QFontDef def = request;
173 def.pixelSize = pixelSize;
175 QFontCache::Key key(def,script);
176 QFontEngine *engine = QFontCache::instance()->findEngine(key);
178 engine = pfdb->fontEngine(def,QUnicodeTables::Script(script),size->handle);
180 QFontCache::Key key(def,script);
181 QFontCache::instance()->instance()->insertEngine(key,engine);
188 QFontEngine *loadEngine(int script, const QFontDef &request,
189 QtFontFamily *family, QtFontFoundry *foundry,
190 QtFontStyle *style, QtFontSize *size)
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 ) {
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));
205 family->askedForFallback = true;
208 QStringList fallbacks = privateDb()->fallbackFamilies;
209 if (family && !family->fallbackFamilies.isEmpty())
210 fallbacks = family->fallbackFamilies;
212 QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
213 QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QUnicodeTables::Script(script));
214 pfMultiEngine->setFallbackFamiliesList(fallbacks);
215 engine = pfMultiEngine;
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);
226 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
228 QFontDatabasePrivate *db = privateDb();
230 fnt->families = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data,fnt->fileName);
232 db->reregisterAppFonts = true;
235 bool QFontDatabase::removeApplicationFont(int handle)
237 QMutexLocker locker(fontDatabaseMutex());
239 QFontDatabasePrivate *db = privateDb();
240 if (handle < 0 || handle >= db->applicationFonts.count())
243 db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
245 db->reregisterAppFonts = true;
250 bool QFontDatabase::removeAllApplicationFonts()
252 QMutexLocker locker(fontDatabaseMutex());
254 QFontDatabasePrivate *db = privateDb();
255 if (db->applicationFonts.isEmpty())
258 db->applicationFonts.clear();
263 bool QFontDatabase::supportsThreadedFontRendering()
272 QFontDatabase::findFont(int script, const QFontPrivate *fp,
273 const QFontDef &request, bool multi)
275 QMutexLocker locker(fontDatabaseMutex());
277 const int force_encoding_id = -1;
279 if (!privateDb()->count)
283 QFontCache::Key key(request, script, multi ? 1 : 0);
284 engine = QFontCache::instance()->findEngine(key);
286 FM_DEBUG("Cache hit level 1");
290 QString family_name, foundry_name;
292 parseFontName(request.family, foundry_name, family_name);
294 if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
295 engine =new QTestFontEngine(request.pixelSize);
296 engine->fontDef = request;
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);
304 FM_DEBUG(" NO MATCH FOUND\n");
307 if (engine && engine->type() != QFontEngine::TestFontEngine) {
308 initFontDef(desc, request, &engine->fontDef, engine->type() == QFontEngine::Multi);
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(',')));
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));
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);
334 match(script, def, def.family, QLatin1String(""), 0, &desc);
335 if (desc.family == 0 && desc.foundry == 0 && desc.style == 0) {
338 engine = loadEngine(script, def, desc.family, desc.foundry, desc.style, desc.size);
340 initFontDef(desc, def, &engine->fontDef, engine->type() == QFontEngine::Multi);
347 engine = new QFontEngineBox(request.pixelSize);
349 FM_DEBUG("returning box engine");
352 if (fp && fp->dpi > 0) {
353 engine->fontDef.pointSize = qreal(double((engine->fontDef.pixelSize * 72) / fp->dpi));
355 engine->fontDef.pointSize = request.pointSize;
361 void QFontDatabase::load(const QFontPrivate *d, int script)
363 QFontDef req = d->request;
365 if (req.pixelSize == -1) {
366 req.pixelSize = floor(((req.pointSize * d->dpi) / 72) * 100 + 0.5) / 100;
367 req.pixelSize = qRound(req.pixelSize);
369 if (req.pointSize < 0)
370 req.pointSize = req.pixelSize*72.0/d->dpi;
372 req.weight = QFont::Normal;
373 if (req.stretch == 0)
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
379 bool multi = !(req.styleStrategy & QFont::NoFontMerging);
380 QFontCache::Key key(req, script, multi ? 1 : 0);
383 getEngineData(d, req);
385 // the cached engineData could have already loaded the engine we want
386 if (d->engineData->engines[script])
389 QFontEngine *fe = QFontCache::instance()->findEngine(key);
391 // list of families to try
392 QStringList family_list;
394 if (!req.family.isEmpty()) {
395 QStringList familiesForRequest = familyList(req);
397 // Add primary selection
398 family_list << familiesForRequest.takeFirst();
400 // Fallbacks requested in font request
401 req.fallBackFamilies = familiesForRequest;
403 // add the default family
404 QString defaultFamily = QGuiApplication::font().family();
405 if (! family_list.contains(defaultFamily))
406 family_list << defaultFamily;
410 // null family means find the first font matching the specified script
411 family_list << QString();
413 QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
414 for (; !fe && it != end; ++it) {
417 fe = QFontDatabase::findFont(script, d, req, multi);
418 if (fe && (fe->type()==QFontEngine::Box) && !req.family.isEmpty()) {
419 if (fe->ref.load() == 0)
425 // No need to check requested fallback families again
426 req.fallBackFamilies.clear();
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;
437 d->engineData->engines[script] = fe;
442 QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
444 return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family);