1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
44 #include "qscreen_qws.h" //so we can check for rotation
45 #include "qwindowsystem_qws.h"
47 #include "qlibraryinfo.h"
48 #include "qabstractfileengine.h"
49 #include <QtCore/qsettings.h>
50 #if !defined(QT_NO_FREETYPE)
51 #include "qfontengine_ft_p.h"
54 #include FT_FREETYPE_H
57 #include "qfontengine_qpf_p.h"
58 #include "private/qfactoryloader_p.h"
59 #include "private/qcore_unix_p.h" // overrides QT_OPEN
60 #include "qabstractfontengine_qws.h"
61 #include "qabstractfontengine_p.h"
62 #include <qdatetime.h>
63 #include "qplatformdefs.h"
68 #include <sys/types.h>
74 #ifdef QT_FONTS_ARE_RESOURCES
75 #include <qresource.h>
81 Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
82 (QFontEngineFactoryInterface_iid, QLatin1String("/fontengines"), Qt::CaseInsensitive))
85 const quint8 DatabaseVersion = 4;
87 // QFontDatabasePrivate::addFont() went into qfontdatabase.cpp
89 #ifndef QT_NO_QWS_QPF2
90 void QFontDatabasePrivate::addQPF2File(const QByteArray &file)
92 #ifndef QT_FONTS_ARE_RESOURCES
94 if (stat(file.constData(), &st))
96 int f = QT_OPEN(file, O_RDONLY, 0);
99 const uchar *data = (const uchar *)mmap(0, st.st_size, PROT_READ, MAP_SHARED, f, 0);
100 const int dataSize = st.st_size;
102 QResource res(QLatin1String(file.constData()));
103 const uchar *data = res.data();
104 const int dataSize = res.size();
105 //qDebug() << "addQPF2File" << file << data;
107 if (data && data != (const uchar *)MAP_FAILED) {
108 if (QFontEngineQPF::verifyHeader(data, dataSize)) {
109 QString fontName = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_FontName).toString();
110 int pixelSize = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_PixelSize).toInt();
111 QVariant weight = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_Weight);
112 QVariant style = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_Style);
113 QByteArray writingSystemBits = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_WritingSystems).toByteArray();
115 if (!fontName.isEmpty() && pixelSize) {
117 if (weight.type() == QVariant::Int || weight.type() == QVariant::UInt)
118 fontWeight = weight.toInt();
120 bool italic = static_cast<QFont::Style>(style.toInt()) & QFont::StyleItalic;
122 QList<QFontDatabase::WritingSystem> writingSystems;
123 for (int i = 0; i < writingSystemBits.count(); ++i) {
124 uchar currentByte = writingSystemBits.at(i);
125 for (int j = 0; j < 8; ++j) {
127 writingSystems << QFontDatabase::WritingSystem(i * 8 + j);
132 addFont(fontName, /*foundry*/ "prerendered", fontWeight, italic,
133 pixelSize, file, /*fileIndex*/ 0,
134 /*antialiased*/ true, writingSystems);
137 qDebug() << "header verification of QPF2 font" << file << "failed. maybe it is corrupt?";
139 #ifndef QT_FONTS_ARE_RESOURCES
140 munmap((void *)data, st.st_size);
143 #ifndef QT_FONTS_ARE_RESOURCES
147 #endif // QT_NO_QWS_QPF2
149 // QFontDatabasePrivate::addTTFile() went into qfontdatabase.cpp
151 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
153 extern QString qws_fontCacheDir();
155 #ifndef QT_FONTS_ARE_RESOURCES
156 bool QFontDatabasePrivate::loadFromCache(const QString &fontPath)
159 const bool weAreTheServer = QWSServer::instance();
161 const bool weAreTheServer = true; // assume single-process
164 QString fontDirFile = fontPath + QLatin1String("/fontdir");
166 QFile binaryDb(qws_fontCacheDir() + QLatin1String("/fontdb"));
168 if (weAreTheServer) {
169 QDateTime dbTimeStamp = QFileInfo(binaryDb.fileName()).lastModified();
171 QDateTime fontPathTimeStamp = QFileInfo(fontPath).lastModified();
172 if (dbTimeStamp < fontPathTimeStamp)
173 return false; // let the caller create the cache
175 if (QFile::exists(fontDirFile)) {
176 QDateTime fontDirTimeStamp = QFileInfo(fontDirFile).lastModified();
177 if (dbTimeStamp < fontDirTimeStamp)
182 if (!binaryDb.open(QIODevice::ReadOnly)) {
184 return false; // let the caller create the cache
185 qFatal("QFontDatabase::loadFromCache: Could not open font database cache!");
188 QDataStream stream(&binaryDb);
190 quint8 dataStreamVersion = 0;
191 stream >> version >> dataStreamVersion;
192 if (version != DatabaseVersion || dataStreamVersion != stream.version()) {
194 return false; // let the caller create the cache
195 qFatal("QFontDatabase::loadFromCache: Wrong version of the font database cache detected. Found %d/%d expected %d/%d",
196 version, dataStreamVersion, DatabaseVersion, stream.version());
199 QString originalFontPath;
200 stream >> originalFontPath;
201 if (originalFontPath != fontPath) {
203 return false; // let the caller create the cache
204 qFatal("QFontDatabase::loadFromCache: Font path doesn't match. Found %s in database, expected %s", qPrintable(originalFontPath), qPrintable(fontPath));
208 stream >> familyname;
209 //qDebug() << "populating database from" << binaryDb.fileName();
210 while (!familyname.isEmpty() && !stream.atEnd()) {
218 quint8 writingSystemCount;
220 QList<QFontDatabase::WritingSystem> writingSystems;
222 stream >> foundryname >> weight >> italic >> pixelSize
223 >> file >> fileIndex >> antialiased >> writingSystemCount;
225 for (quint8 i = 0; i < writingSystemCount; ++i) {
228 writingSystems.append(QFontDatabase::WritingSystem(ws));
231 addFont(familyname, foundryname.toLatin1().constData(), weight, italic, pixelSize, file, fileIndex, antialiased,
234 stream >> familyname;
237 stream >> fallbackFamilies;
238 //qDebug() << "fallback families from cache:" << fallbackFamilies;
241 #endif // QT_FONTS_ARE_RESOURCES
247 static QString qwsFontPath()
249 QString fontpath = QString::fromLocal8Bit(qgetenv("QT_QWS_FONTDIR"));
250 if (fontpath.isEmpty()) {
251 #ifdef QT_FONTS_ARE_RESOURCES
252 fontpath = QLatin1String(":/qt/fonts");
254 #ifndef QT_NO_SETTINGS
255 fontpath = QLibraryInfo::location(QLibraryInfo::LibrariesPath);
256 fontpath += QLatin1String("/fonts");
258 fontpath = QLatin1String("/lib/fonts");
260 #endif //QT_FONTS_ARE_RESOURCES
266 #if defined(QFONTDATABASE_DEBUG) && defined(QT_FONTS_ARE_RESOURCES)
267 class FriendlyResource : public QResource
270 bool isDir () const { return QResource::isDir(); }
271 bool isFile () const { return QResource::isFile(); }
272 QStringList children () const { return QResource::children(); }
278 static void initializeDb()
280 QFontDatabasePrivate *db = privateDb();
281 if (!db || db->count)
284 QString fontpath = qwsFontPath();
285 #ifndef QT_FONTS_ARE_RESOURCES
286 QString fontDirFile = fontpath + QLatin1String("/fontdir");
288 if(!QFile::exists(fontpath)) {
289 qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
290 fontpath.toLocal8Bit().constData());
293 const bool loaded = db->loadFromCache(fontpath);
295 if (db->reregisterAppFonts) {
296 db->reregisterAppFonts = false;
297 for (int i = 0; i < db->applicationFonts.count(); ++i)
298 if (!db->applicationFonts.at(i).families.isEmpty()) {
299 registerFont(&db->applicationFonts[i]);
306 QString dbFileName = qws_fontCacheDir() + QLatin1String("/fontdb");
308 QFile binaryDb(dbFileName + QLatin1String(".tmp"));
309 binaryDb.open(QIODevice::WriteOnly | QIODevice::Truncate);
310 db->stream = new QDataStream(&binaryDb);
311 *db->stream << DatabaseVersion << quint8(db->stream->version()) << fontpath;
312 // qDebug() << "creating binary database at" << binaryDb.fileName();
314 // Load in font definition file
315 FILE* fontdef=fopen(fontDirFile.toLocal8Bit().constData(),"r");
321 char isitalic[10]="";
324 fgets(buf,200,fontdef);
328 sscanf(buf,"%s %s %s %s %d %d %s",name,file,render,isitalic,&weight,&size,flags);
331 filename.append(fontpath).append(QLatin1Char('/'));
332 filename += QLatin1String(file);
333 bool italic = isitalic[0] == 'y';
334 bool smooth = QByteArray(flags).contains('s');
335 if (file[0] && QFile::exists(filename))
336 db->addFont(QString::fromUtf8(name), /*foundry*/"", weight, italic, size/10, QFile::encodeName(filename), /*fileIndex*/ 0, smooth);
338 } while (!feof(fontdef));
343 QDir dir(fontpath, QLatin1String("*.qpf"));
344 for (int i=0; i<int(dir.count()); i++) {
345 int u0 = dir[i].indexOf(QLatin1Char('_'));
346 int u1 = dir[i].indexOf(QLatin1Char('_'), u0+1);
347 int u2 = dir[i].indexOf(QLatin1Char('_'), u1+1);
348 int u3 = dir[i].indexOf(QLatin1Char('.'), u1+1);
351 QString familyname = dir[i].left(u0);
352 int pixelSize = dir[i].mid(u0+1,u1-u0-1).toInt()/10;
353 bool italic = dir[i].mid(u2-1,1) == QLatin1String("i");
354 int weight = dir[i].mid(u1+1,u2-u1-1-(italic?1:0)).toInt();
356 db->addFont(familyname, /*foundry*/ "qt", weight, italic, pixelSize, QFile::encodeName(dir.absoluteFilePath(dir[i])),
357 /*fileIndex*/ 0, /*antialiased*/ true);
360 #ifndef QT_NO_FREETYPE
361 dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
362 << QLatin1String("*.ttc") << QLatin1String("*.pfa")
363 << QLatin1String("*.pfb"));
365 for (int i = 0; i < int(dir.count()); ++i) {
366 const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
367 // qDebug() << "looking at" << file;
372 #ifndef QT_NO_QWS_QPF2
373 dir.setNameFilters(QStringList() << QLatin1String("*.qpf2"));
375 for (int i = 0; i < int(dir.count()); ++i) {
376 const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
377 // qDebug() << "looking at" << file;
378 db->addQPF2File(file);
382 #else //QT_FONTS_ARE_RESOURCES
383 #ifdef QFONTDATABASE_DEBUG
385 QResource fontdir(fontpath);
386 FriendlyResource *fr = static_cast<FriendlyResource*>(&fontdir);
387 qDebug() << "fontdir" << fr->isValid() << fr->isDir() << fr->children();
391 #ifndef QT_NO_QWS_QPF2
392 QDir dir(fontpath, QLatin1String("*.qpf2"));
393 for (int i = 0; i < int(dir.count()); ++i) {
394 const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
395 //qDebug() << "looking at" << file;
396 db->addQPF2File(file);
399 #endif //QT_FONTS_ARE_RESOURCES
402 #ifdef QFONTDATABASE_DEBUG
403 // print the database
404 for (int f = 0; f < db->count; f++) {
405 QtFontFamily *family = db->families[f];
406 FD_DEBUG("'%s' %s", qPrintable(family->name), (family->fixedPitch ? "fixed" : ""));
408 for (int i = 0; i < QFont::LastPrivateScript; ++i) {
409 FD_DEBUG("\t%s: %s", qPrintable(QFontDatabase::scriptName((QFont::Script) i)),
410 ((family->scripts[i] & QtFontFamily::Supported) ? "Supported" :
411 (family->scripts[i] & QtFontFamily::UnSupported) == QtFontFamily::UnSupported ?
412 "UnSupported" : "Unknown"));
416 for (int fd = 0; fd < family->count; fd++) {
417 QtFontFoundry *foundry = family->foundries[fd];
418 FD_DEBUG("\t\t'%s'", qPrintable(foundry->name));
419 for (int s = 0; s < foundry->count; s++) {
420 QtFontStyle *style = foundry->styles[s];
421 FD_DEBUG("\t\t\tstyle: style=%d weight=%d\n"
423 style->key.style, style->key.weight,
425 if (style->smoothScalable)
426 FD_DEBUG("\t\t\t\tsmooth scalable");
427 else if (style->bitmapScalable)
428 FD_DEBUG("\t\t\t\tbitmap scalable");
429 if (style->pixelSizes) {
430 FD_DEBUG("\t\t\t\t%d pixel sizes", style->count);
431 for (int z = 0; z < style->count; ++z) {
432 QtFontSize *size = style->pixelSizes + z;
433 FD_DEBUG("\t\t\t\t size %5d",
440 #endif // QFONTDATABASE_DEBUG
442 #ifndef QT_NO_LIBRARY
443 QStringList pluginFoundries = loader()->keys();
444 // qDebug() << "plugin foundries:" << pluginFoundries;
445 for (int i = 0; i < pluginFoundries.count(); ++i) {
446 const QString foundry(pluginFoundries.at(i));
448 QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry));
450 qDebug() << "Could not load plugin for foundry" << foundry;
454 QList<QFontEngineInfo> fonts = factory->availableFontEngines();
455 for (int i = 0; i < fonts.count(); ++i) {
456 QFontEngineInfo info = fonts.at(i);
458 int weight = info.weight();
460 weight = QFont::Normal;
462 db->addFont(info.family(), foundry.toLatin1().constData(),
463 weight, info.style() != QFont::StyleNormal,
464 qRound(info.pixelSize()), /*file*/QByteArray(),
465 /*fileIndex*/0, /*antiAliased*/true,
466 info.writingSystems());
471 #ifndef QT_FONTS_ARE_RESOURCES
472 // the empty string/familyname signifies the end of the font list.
473 *db->stream << QString();
476 bool coveredWritingSystems[QFontDatabase::WritingSystemsCount] = { 0 };
478 db->fallbackFamilies.clear();
480 for (int i = 0; i < db->count; ++i) {
481 QtFontFamily *family = db->families[i];
483 if (family->count == 0)
485 if (family->bogusWritingSystems)
487 for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
488 if (coveredWritingSystems[ws])
490 if (family->writingSystems[ws] & QtFontFamily::Supported) {
491 coveredWritingSystems[ws] = true;
496 db->fallbackFamilies << family->name;
498 //qDebug() << "fallbacks on the server:" << db->fallbackFamilies;
499 #ifndef QT_FONTS_ARE_RESOURCES
500 *db->stream << db->fallbackFamilies;
503 #ifndef QT_FONTS_ARE_RESOURCES
506 QFile::remove(dbFileName);
507 binaryDb.rename(dbFileName);
511 // called from qwindowsystem_qws.cpp
512 void qt_qws_init_fontdb()
517 #ifndef QT_NO_SETTINGS
518 // called from qapplication_qws.cpp
519 void qt_applyFontDatabaseSettings(const QSettings &settings)
522 QFontDatabasePrivate *db = privateDb();
523 for (int i = 0; i < db->count; ++i) {
524 QtFontFamily *family = db->families[i];
525 if (settings.contains(family->name))
526 family->fallbackFamilies = settings.value(family->name).toStringList();
529 if (settings.contains(QLatin1String("Global Fallbacks")))
530 db->fallbackFamilies = settings.value(QLatin1String("Global Fallbacks")).toStringList();
532 #endif // QT_NO_SETTINGS
534 static inline void load(const QString & = QString(), int = -1)
539 #ifndef QT_NO_FREETYPE
541 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
542 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
543 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
545 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
546 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
549 #endif // QT_NO_FREETYPE
552 QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp,
553 const QFontDef &request,
554 QtFontFamily *family, QtFontFoundry *foundry,
555 QtFontStyle *style, QtFontSize *size)
559 #ifdef QT_NO_FREETYPE
567 int pixelSize = size->pixelSize;
568 if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE))
569 pixelSize = request.pixelSize;
571 #ifndef QT_NO_QWS_QPF2
572 if (foundry->name == QLatin1String("prerendered")) {
573 #ifdef QT_FONTS_ARE_RESOURCES
574 QResource res(QLatin1String(size->fileName.constData()));
576 QFontEngineQPF *fe = new QFontEngineQPF(request, res.data(), res.size());
580 qDebug() << "fontengine is not valid! " << size->fileName;
582 qDebug() << "Resource not valid" << size->fileName;
585 int f = ::open(size->fileName, O_RDONLY, 0);
587 QFontEngineQPF *fe = new QFontEngineQPF(request, f);
590 delete fe; // will close f
591 qDebug() << "fontengine is not valid!";
596 if ( foundry->name != QLatin1String("qt") ) { ///#### is this the best way????
597 QString file = QFile::decodeName(size->fileName);
599 QFontDef def = request;
600 def.pixelSize = pixelSize;
602 #ifdef QT_NO_QWS_SHARE_FONTS
603 bool shareFonts = false;
605 static bool dontShareFonts = !qgetenv("QWS_NO_SHARE_FONTS").isEmpty();
606 bool shareFonts = !dontShareFonts;
609 QScopedPointer<QFontEngine> engine;
611 #ifndef QT_NO_LIBRARY
612 QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry->name));
614 QFontEngineInfo info;
615 info.setFamily(request.family);
616 info.setPixelSize(request.pixelSize);
617 info.setStyle(QFont::Style(request.style));
618 info.setWeight(request.weight);
621 QAbstractFontEngine *customEngine = factory->create(info);
623 engine.reset(new QProxyFontEngine(customEngine, def));
626 QVariant hint = customEngine->fontProperty(QAbstractFontEngine::CacheGlyphsHint);
628 shareFonts = hint.toBool();
630 shareFonts = (pixelSize < 64);
634 #endif // QT_NO_LIBRARY
635 if ((engine.isNull() && !file.isEmpty() && QFile::exists(file)) || privateDb()->isApplicationFont(file)) {
636 QFontEngine::FaceId faceId;
637 faceId.filename = file.toLocal8Bit();
638 faceId.index = size->fileIndex;
640 #ifndef QT_NO_FREETYPE
642 QScopedPointer<QFontEngineFT> fte(new QFontEngineFT(def));
643 bool antialias = style->antialiased && !(request.styleStrategy & QFont::NoAntialias);
644 if (fte->init(faceId, antialias,
645 antialias ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono)) {
646 #ifdef QT_NO_QWS_QPF2
649 // try to distinguish between bdf and ttf fonts we can pre-render
650 // and don't try to share outline fonts
651 shareFonts = shareFonts
652 && !fte->defaultGlyphs()->outline_drawing
653 && !fte->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd')).isEmpty();
654 engine.reset(fte.take());
657 #endif // QT_NO_FREETYPE
659 if (!engine.isNull()) {
660 #if !defined(QT_NO_QWS_QPF2) && !defined(QT_FONTS_ARE_RESOURCES)
662 QScopedPointer<QFontEngineQPF> fe(new QFontEngineQPF(def, -1, engine.data()));
666 qWarning("Initializing QFontEngineQPF failed for %s", qPrintable(file));
667 engine.reset(fe->takeRenderingEngine());
670 return engine.take();
674 #ifndef QT_NO_QWS_QPF
675 QString fn = qwsFontPath();
676 fn += QLatin1Char('/');
677 fn += family->name.toLower()
678 + QLatin1Char('_') + QString::number(pixelSize*10)
679 + QLatin1Char('_') + QString::number(style->key.weight)
680 + (style->key.style == QFont::StyleItalic ?
681 QLatin1String("i.qpf") : QLatin1String(".qpf"));
684 QFontEngine *fe = new QFontEngineQPF1(request, fn);
686 #endif // QT_NO_QWS_QPF
688 return new QFontEngineBox(pixelSize);
692 QFontEngine *loadEngine(int script, const QFontPrivate *fp,
693 const QFontDef &request,
694 QtFontFamily *family, QtFontFoundry *foundry,
695 QtFontStyle *style, QtFontSize *size)
697 QScopedPointer<QFontEngine> engine(loadSingleEngine(script, fp, request, family, foundry,
699 #ifndef QT_NO_QWS_QPF
701 && script == QUnicodeTables::Common
702 && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
704 QStringList fallbacks = privateDb()->fallbackFamilies;
706 if (family && !family->fallbackFamilies.isEmpty())
707 fallbacks = family->fallbackFamilies;
709 QFontEngine *fe = new QFontEngineMultiQWS(engine.data(), script, fallbacks);
714 return engine.take();
717 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
719 QFontDatabasePrivate *db = privateDb();
720 #ifdef QT_NO_FREETYPE
723 fnt->families = db->addTTFile(QFile::encodeName(fnt->fileName), fnt->data);
724 db->fallbackFamilies += fnt->families;
726 db->reregisterAppFonts = true;
729 bool QFontDatabase::removeApplicationFont(int handle)
731 QMutexLocker locker(fontDatabaseMutex());
733 QFontDatabasePrivate *db = privateDb();
734 if (handle < 0 || handle >= db->applicationFonts.count())
737 db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
739 db->reregisterAppFonts = true;
744 bool QFontDatabase::removeAllApplicationFonts()
746 QMutexLocker locker(fontDatabaseMutex());
748 QFontDatabasePrivate *db = privateDb();
749 if (db->applicationFonts.isEmpty())
752 db->applicationFonts.clear();
757 bool QFontDatabase::supportsThreadedFontRendering()
763 QFontDatabase::findFont(int script, const QFontPrivate *fp,
764 const QFontDef &request)
766 QMutexLocker locker(fontDatabaseMutex());
768 const int force_encoding_id = -1;
770 if (!privateDb()->count)
773 QScopedPointer<QFontEngine> fe;
776 fe.reset(loadEngine(script, fp, request, 0, 0, 0, 0));
778 // if we fail to load the rawmode font, use a 12pixel box engine instead
780 fe.reset(new QFontEngineBox(12));
784 QFontCache::Key key(request, script);
785 fe.reset(QFontCache::instance()->findEngine(key));
790 QString family_name, foundry_name;
791 QtFontStyle::Key styleKey;
792 styleKey.style = request.style;
793 styleKey.weight = request.weight;
794 styleKey.stretch = request.stretch;
795 char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
797 parseFontName(request.family, foundry_name, family_name);
799 FM_DEBUG("QFontDatabase::findFont\n"
801 " family: %s [%s], script: %d\n"
802 " weight: %d, style: %d\n"
806 family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
807 foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
808 script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
810 if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
811 fe.reset(new QTestFontEngine(request.pixelSize));
812 fe->fontDef = request;
818 match(script, request, family_name, foundry_name, force_encoding_id, &desc);
820 if (desc.family != 0 && desc.foundry != 0 && desc.style != 0
824 " weight: %d, style: %d\n"
829 desc.family->name.toLatin1().constData(),
830 desc.foundry->name.isEmpty() ? "-- none --" : desc.foundry->name.toLatin1().constData(),
831 desc.style->key.weight, desc.style->key.style,
832 desc.style->key.stretch, desc.size ? desc.size->pixelSize : 0xffff,
836 fe.reset(loadEngine(script, fp, request, desc.family, desc.foundry, desc.style, desc.size
839 FM_DEBUG(" NO MATCH FOUND\n");
842 initFontDef(desc, request, &fe->fontDef);
845 #ifndef QT_NO_FREETYPE
847 if (scriptRequiresOpenType(script) && fe->type() == QFontEngine::Freetype) {
848 HB_Face hbFace = static_cast<QFontEngineFT *>(fe.data())->harfbuzzFace();
849 if (!hbFace || !hbFace->supported_scripts[script]) {
850 FM_DEBUG(" OpenType support missing for script\n");
859 QFontDef def = request;
860 if (def.family.isEmpty()) {
861 def.family = fp->request.family;
862 def.family = def.family.left(def.family.indexOf(QLatin1Char(',')));
864 QFontCache::Key key(def, script);
865 QFontCache::instance()->insertEngine(key, fe.data());
870 if (!request.family.isEmpty())
873 FM_DEBUG("returning box engine");
875 fe.reset(new QFontEngineBox(request.pixelSize));
878 QFontCache::Key key(request, script);
879 QFontCache::instance()->insertEngine(key, fe.data());
883 if (fp && fp->dpi > 0) {
884 fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / fp->dpi));
886 fe->fontDef.pointSize = request.pointSize;
892 void QFontDatabase::load(const QFontPrivate *d, int script)
894 QFontDef req = d->request;
896 if (req.pixelSize == -1)
897 req.pixelSize = qRound(req.pointSize*d->dpi/72);
898 if (req.pointSize < 0)
899 req.pointSize = req.pixelSize*72.0/d->dpi;
901 if (!d->engineData) {
902 QFontCache::Key key(req, script);
904 // look for the requested font in the engine data cache
905 d->engineData = QFontCache::instance()->findEngineData(key);
907 if (!d->engineData) {
909 d->engineData = new QFontEngineData;
911 QFontCache::instance()->insertEngineData(key, d->engineData);
913 delete d->engineData;
918 d->engineData->ref.ref();
922 // the cached engineData could have already loaded the engine we want
923 if (d->engineData->engines[script]) return;
925 // double scale = 1.0; // ### TODO: fix the scale calculations
927 // list of families to try
928 QStringList family_list;
930 if (!req.family.isEmpty()) {
931 family_list = req.family.split(QLatin1Char(','));
933 // append the substitute list for each family in family_list
934 QStringList subs_list;
935 QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
936 for (; it != end; ++it)
937 subs_list += QFont::substitutes(*it);
938 family_list += subs_list;
940 // append the default fallback font for the specified script
941 // family_list << ... ; ###########
943 // add the default family
944 QString defaultFamily = QApplication::font().family();
945 if (! family_list.contains(defaultFamily))
946 family_list << defaultFamily;
948 // add QFont::defaultFamily() to the list, for compatibility with
950 family_list << QApplication::font().defaultFamily();
953 // null family means find the first font matching the specified script
954 family_list << QString();
957 QFontEngine *engine = 0;
958 QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
959 for (; !engine && it != end; ++it) {
962 engine = QFontDatabase::findFont(script, d, req);
963 if (engine && (engine->type()==QFontEngine::Box) && !req.family.isEmpty())
968 d->engineData->engines[script] = engine;