Fix uses of qRound on non-floating-point types.
[profile/ivi/qtbase.git] / src / gui / text / qfontdatabase_qws.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui 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 "qdir.h"
43 #if defined(Q_WS_QWS)
44 #include "qscreen_qws.h" //so we can check for rotation
45 #include "qwindowsystem_qws.h"
46 #endif
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"
52
53 #include <ft2build.h>
54 #include FT_FREETYPE_H
55
56 #endif
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"
64
65 // for mmap
66 #include <stdlib.h>
67 #include <unistd.h>
68 #include <sys/types.h>
69 #include <sys/stat.h>
70 #include <sys/mman.h>
71 #include <fcntl.h>
72 #include <errno.h>
73
74 #ifdef QT_FONTS_ARE_RESOURCES
75 #include <qresource.h>
76 #endif
77
78 QT_BEGIN_NAMESPACE
79
80 #ifndef QT_NO_LIBRARY
81 Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
82     (QFontEngineFactoryInterface_iid, QLatin1String("/fontengines"), Qt::CaseInsensitive))
83 #endif
84
85 const quint8 DatabaseVersion = 4;
86
87 // QFontDatabasePrivate::addFont() went into qfontdatabase.cpp
88
89 #ifndef QT_NO_QWS_QPF2
90 void QFontDatabasePrivate::addQPF2File(const QByteArray &file)
91 {
92 #ifndef QT_FONTS_ARE_RESOURCES
93     struct stat st;
94     if (stat(file.constData(), &st))
95         return;
96     int f = QT_OPEN(file, O_RDONLY, 0);
97     if (f < 0)
98         return;
99     const uchar *data = (const uchar *)mmap(0, st.st_size, PROT_READ, MAP_SHARED, f, 0);
100     const int dataSize = st.st_size;
101 #else
102     QResource res(QLatin1String(file.constData()));
103     const uchar *data = res.data();
104     const int dataSize = res.size();
105     //qDebug() << "addQPF2File" << file << data;
106 #endif
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();
114
115             if (!fontName.isEmpty() && pixelSize) {
116                 int fontWeight = 50;
117                 if (weight.type() == QVariant::Int || weight.type() == QVariant::UInt)
118                     fontWeight = weight.toInt();
119
120                 bool italic = static_cast<QFont::Style>(style.toInt()) & QFont::StyleItalic;
121
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) {
126                         if (currentByte & 1)
127                             writingSystems << QFontDatabase::WritingSystem(i * 8 + j);
128                         currentByte >>= 1;
129                     }
130                 }
131
132                 addFont(fontName, /*foundry*/ "prerendered", fontWeight, italic,
133                         pixelSize, file, /*fileIndex*/ 0,
134                         /*antialiased*/ true, writingSystems);
135             }
136         } else {
137             qDebug() << "header verification of QPF2 font" << file << "failed. maybe it is corrupt?";
138         }
139 #ifndef QT_FONTS_ARE_RESOURCES
140         munmap((void *)data, st.st_size);
141 #endif
142     }
143 #ifndef QT_FONTS_ARE_RESOURCES
144     QT_CLOSE(f);
145 #endif
146 }
147 #endif // QT_NO_QWS_QPF2
148
149 // QFontDatabasePrivate::addTTFile() went into qfontdatabase.cpp
150
151 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
152
153 extern QString qws_fontCacheDir();
154
155 #ifndef QT_FONTS_ARE_RESOURCES
156 bool QFontDatabasePrivate::loadFromCache(const QString &fontPath)
157 {
158 #ifdef Q_WS_QWS
159     const bool weAreTheServer = QWSServer::instance();
160 #else
161     const bool weAreTheServer = true; // assume single-process
162 #endif
163
164     QString fontDirFile = fontPath + QLatin1String("/fontdir");
165
166     QFile binaryDb(qws_fontCacheDir() + QLatin1String("/fontdb"));
167
168     if (weAreTheServer) {
169         QDateTime dbTimeStamp = QFileInfo(binaryDb.fileName()).lastModified();
170
171         QDateTime fontPathTimeStamp = QFileInfo(fontPath).lastModified();
172         if (dbTimeStamp < fontPathTimeStamp)
173             return false; // let the caller create the cache
174
175         if (QFile::exists(fontDirFile)) {
176             QDateTime fontDirTimeStamp = QFileInfo(fontDirFile).lastModified();
177             if (dbTimeStamp < fontDirTimeStamp)
178                 return false;
179         }
180     }
181
182     if (!binaryDb.open(QIODevice::ReadOnly)) {
183         if (weAreTheServer)
184             return false; // let the caller create the cache
185         qFatal("QFontDatabase::loadFromCache: Could not open font database cache!");
186     }
187
188     QDataStream stream(&binaryDb);
189     quint8 version = 0;
190     quint8 dataStreamVersion = 0;
191     stream >> version >> dataStreamVersion;
192     if (version != DatabaseVersion || dataStreamVersion != stream.version()) {
193         if (weAreTheServer)
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());
197     }
198
199     QString originalFontPath;
200     stream >> originalFontPath;
201     if (originalFontPath != fontPath) {
202         if (weAreTheServer)
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));
205     }
206
207     QString familyname;
208     stream >> familyname;
209     //qDebug() << "populating database from" << binaryDb.fileName();
210     while (!familyname.isEmpty() && !stream.atEnd()) {
211         QString foundryname;
212         int weight;
213         quint8 italic;
214         int pixelSize;
215         QByteArray file;
216         int fileIndex;
217         quint8 antialiased;
218         quint8 writingSystemCount;
219
220         QList<QFontDatabase::WritingSystem> writingSystems;
221
222         stream >> foundryname >> weight >> italic >> pixelSize
223                >> file >> fileIndex >> antialiased >> writingSystemCount;
224
225         for (quint8 i = 0; i < writingSystemCount; ++i) {
226             quint8 ws;
227             stream >> ws;
228             writingSystems.append(QFontDatabase::WritingSystem(ws));
229         }
230
231         addFont(familyname, foundryname.toLatin1().constData(), weight, italic, pixelSize, file, fileIndex, antialiased,
232                 writingSystems);
233
234         stream >> familyname;
235     }
236
237     stream >> fallbackFamilies;
238     //qDebug() << "fallback families from cache:" << fallbackFamilies;
239     return true;
240 }
241 #endif // QT_FONTS_ARE_RESOURCES
242
243 /*!
244     \internal
245 */
246
247 static QString qwsFontPath()
248 {
249     QString fontpath = QString::fromLocal8Bit(qgetenv("QT_QWS_FONTDIR"));
250     if (fontpath.isEmpty()) {
251 #ifdef QT_FONTS_ARE_RESOURCES
252         fontpath = QLatin1String(":/qt/fonts");
253 #else
254 #ifndef QT_NO_SETTINGS
255         fontpath = QLibraryInfo::location(QLibraryInfo::LibrariesPath);
256         fontpath += QLatin1String("/fonts");
257 #else
258         fontpath = QLatin1String("/lib/fonts");
259 #endif
260 #endif //QT_FONTS_ARE_RESOURCES
261     }
262
263     return fontpath;
264 }
265
266 #if defined(QFONTDATABASE_DEBUG) && defined(QT_FONTS_ARE_RESOURCES)
267 class FriendlyResource : public QResource
268 {
269 public:
270     bool isDir () const { return QResource::isDir(); }
271     bool isFile () const { return QResource::isFile(); }
272     QStringList children () const { return QResource::children(); }
273 };
274 #endif
275 /*!
276     \internal
277 */
278 static void initializeDb()
279 {
280     QFontDatabasePrivate *db = privateDb();
281     if (!db || db->count)
282         return;
283
284     QString fontpath = qwsFontPath();
285 #ifndef QT_FONTS_ARE_RESOURCES
286     QString fontDirFile = fontpath + QLatin1String("/fontdir");
287
288     if(!QFile::exists(fontpath)) {
289         qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
290                fontpath.toLocal8Bit().constData());
291     }
292
293     const bool loaded = db->loadFromCache(fontpath);
294
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]);
300             }
301     }
302
303     if (loaded)
304         return;
305
306     QString dbFileName = qws_fontCacheDir() + QLatin1String("/fontdb");
307
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();
313
314     // Load in font definition file
315     FILE* fontdef=fopen(fontDirFile.toLocal8Bit().constData(),"r");
316     if (fontdef) {
317         char buf[200]="";
318         char name[200]="";
319         char render[200]="";
320         char file[200]="";
321         char isitalic[10]="";
322         char flags[10]="";
323         do {
324             fgets(buf,200,fontdef);
325             if (buf[0] != '#') {
326                 int weight=50;
327                 int size=0;
328                 sscanf(buf,"%s %s %s %s %d %d %s",name,file,render,isitalic,&weight,&size,flags);
329                 QString filename;
330                 if (file[0] != '/')
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);
337             }
338         } while (!feof(fontdef));
339         fclose(fontdef);
340     }
341
342
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);
349         if (u2 < 0) u2 = u3;
350
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();
355
356         db->addFont(familyname, /*foundry*/ "qt", weight, italic, pixelSize, QFile::encodeName(dir.absoluteFilePath(dir[i])),
357                     /*fileIndex*/ 0, /*antialiased*/ true);
358     }
359
360 #ifndef QT_NO_FREETYPE
361     dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
362                        << QLatin1String("*.ttc") << QLatin1String("*.pfa")
363                        << QLatin1String("*.pfb"));
364     dir.refresh();
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;
368         db->addTTFile(file);
369     }
370 #endif
371
372 #ifndef QT_NO_QWS_QPF2
373     dir.setNameFilters(QStringList() << QLatin1String("*.qpf2"));
374     dir.refresh();
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);
379     }
380 #endif
381
382 #else //QT_FONTS_ARE_RESOURCES
383 #ifdef QFONTDATABASE_DEBUG
384     {
385         QResource fontdir(fontpath);
386         FriendlyResource *fr = static_cast<FriendlyResource*>(&fontdir);
387         qDebug() << "fontdir" << fr->isValid() << fr->isDir() << fr->children();
388
389     }
390 #endif
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);
397     }
398 #endif
399 #endif //QT_FONTS_ARE_RESOURCES
400
401
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" : ""));
407 #if 0
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"));
413         }
414 #endif
415
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"
422                          "\t\t\tstretch=%d",
423                          style->key.style, style->key.weight,
424                          style->key.stretch);
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",
434                                   size->pixelSize);
435                     }
436                 }
437             }
438         }
439     }
440 #endif // QFONTDATABASE_DEBUG
441
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));
447
448         QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry));
449         if (!factory) {
450             qDebug() << "Could not load plugin for foundry" << foundry;
451             continue;
452         }
453
454         QList<QFontEngineInfo> fonts = factory->availableFontEngines();
455         for (int i = 0; i < fonts.count(); ++i) {
456             QFontEngineInfo info = fonts.at(i);
457
458             int weight = info.weight();
459             if (weight <= 0)
460                 weight = QFont::Normal;
461
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());
467         }
468     }
469 #endif
470
471 #ifndef QT_FONTS_ARE_RESOURCES
472     // the empty string/familyname signifies the end of the font list.
473     *db->stream << QString();
474 #endif
475     {
476         bool coveredWritingSystems[QFontDatabase::WritingSystemsCount] = { 0 };
477
478         db->fallbackFamilies.clear();
479
480         for (int i = 0; i < db->count; ++i) {
481             QtFontFamily *family = db->families[i];
482             bool add = false;
483             if (family->count == 0)
484                 continue;
485             if (family->bogusWritingSystems)
486                 continue;
487             for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
488                 if (coveredWritingSystems[ws])
489                     continue;
490                 if (family->writingSystems[ws] & QtFontFamily::Supported) {
491                     coveredWritingSystems[ws] = true;
492                     add = true;
493                 }
494             }
495             if (add)
496                 db->fallbackFamilies << family->name;
497         }
498         //qDebug() << "fallbacks on the server:" << db->fallbackFamilies;
499 #ifndef QT_FONTS_ARE_RESOURCES
500         *db->stream << db->fallbackFamilies;
501 #endif
502     }
503 #ifndef QT_FONTS_ARE_RESOURCES
504     delete db->stream;
505     db->stream = 0;
506     QFile::remove(dbFileName);
507     binaryDb.rename(dbFileName);
508 #endif
509 }
510
511 // called from qwindowsystem_qws.cpp
512 void qt_qws_init_fontdb()
513 {
514     initializeDb();
515 }
516
517 #ifndef QT_NO_SETTINGS
518 // called from qapplication_qws.cpp
519 void qt_applyFontDatabaseSettings(const QSettings &settings)
520 {
521     initializeDb();
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();
527     }
528
529     if (settings.contains(QLatin1String("Global Fallbacks")))
530         db->fallbackFamilies = settings.value(QLatin1String("Global Fallbacks")).toStringList();
531 }
532 #endif // QT_NO_SETTINGS
533
534 static inline void load(const QString & = QString(), int = -1)
535 {
536     initializeDb();
537 }
538
539 #ifndef QT_NO_FREETYPE
540
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)
544 #else
545 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
546 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
547 #endif
548
549 #endif // QT_NO_FREETYPE
550
551 static
552 QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp,
553                               const QFontDef &request,
554                               QtFontFamily *family, QtFontFoundry *foundry,
555                               QtFontStyle *style, QtFontSize *size)
556 {
557     Q_UNUSED(script);
558     Q_UNUSED(fp);
559 #ifdef QT_NO_FREETYPE
560     Q_UNUSED(foundry);
561 #endif
562 #ifdef QT_NO_QWS_QPF
563     Q_UNUSED(family);
564 #endif
565     Q_ASSERT(size);
566
567     int pixelSize = size->pixelSize;
568     if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE))
569         pixelSize = request.pixelSize;
570
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()));
575         if (res.isValid()) {
576             QFontEngineQPF *fe = new QFontEngineQPF(request, res.data(), res.size());
577             if (fe->isValid())
578                 return fe;
579             delete fe;
580             qDebug() << "fontengine is not valid! " << size->fileName;
581         } else {
582             qDebug() << "Resource not valid" << size->fileName;
583         }
584 #else
585         int f = ::open(size->fileName, O_RDONLY, 0);
586         if (f >= 0) {
587             QFontEngineQPF *fe = new QFontEngineQPF(request, f);
588             if (fe->isValid())
589                 return fe;
590             delete fe; // will close f
591             qDebug() << "fontengine is not valid!";
592         }
593 #endif
594     } else
595 #endif
596     if ( foundry->name != QLatin1String("qt") ) { ///#### is this the best way????
597         QString file = QFile::decodeName(size->fileName);
598
599         QFontDef def = request;
600         def.pixelSize = pixelSize;
601
602 #ifdef QT_NO_QWS_SHARE_FONTS
603         bool shareFonts = false;
604 #else
605         static bool dontShareFonts = !qgetenv("QWS_NO_SHARE_FONTS").isEmpty();
606         bool shareFonts = !dontShareFonts;
607 #endif
608
609         QScopedPointer<QFontEngine> engine;
610
611 #ifndef QT_NO_LIBRARY
612         QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry->name));
613         if (factory) {
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);
619             // #### antialiased
620
621             QAbstractFontEngine *customEngine = factory->create(info);
622             if (customEngine) {
623                 engine.reset(new QProxyFontEngine(customEngine, def));
624
625                 if (shareFonts) {
626                     QVariant hint = customEngine->fontProperty(QAbstractFontEngine::CacheGlyphsHint);
627                     if (hint.isValid())
628                         shareFonts = hint.toBool();
629                     else
630                         shareFonts = (pixelSize < 64);
631                 }
632             }
633         }
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;
639
640 #ifndef QT_NO_FREETYPE
641
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
647                 return fte.take();
648 #else
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());
655 #endif
656             }
657 #endif // QT_NO_FREETYPE
658         }
659         if (!engine.isNull()) {
660 #if !defined(QT_NO_QWS_QPF2) && !defined(QT_FONTS_ARE_RESOURCES)
661             if (shareFonts) {
662                 QScopedPointer<QFontEngineQPF> fe(new QFontEngineQPF(def, -1, engine.data()));
663                 engine.take();
664                 if (fe->isValid())
665                     return fe.take();
666                 qWarning("Initializing QFontEngineQPF failed for %s", qPrintable(file));
667                 engine.reset(fe->takeRenderingEngine());
668             }
669 #endif
670             return engine.take();
671         }
672     } else
673     {
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"));
682         //###rotation ###
683
684         QFontEngine *fe = new QFontEngineQPF1(request, fn);
685         return fe;
686 #endif // QT_NO_QWS_QPF
687     }
688     return new QFontEngineBox(pixelSize);
689 }
690
691 static
692 QFontEngine *loadEngine(int script, const QFontPrivate *fp,
693                         const QFontDef &request,
694                         QtFontFamily *family, QtFontFoundry *foundry,
695                         QtFontStyle *style, QtFontSize *size)
696 {
697     QScopedPointer<QFontEngine> engine(loadSingleEngine(script, fp, request, family, foundry,
698                                        style, size));
699 #ifndef QT_NO_QWS_QPF
700     if (!engine.isNull()
701         && script == QUnicodeTables::Common
702         && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
703
704         QStringList fallbacks = privateDb()->fallbackFamilies;
705
706         if (family && !family->fallbackFamilies.isEmpty())
707             fallbacks = family->fallbackFamilies;
708
709         QFontEngine *fe = new QFontEngineMultiQWS(engine.data(), script, fallbacks);
710         engine.take();
711         engine.reset(fe);
712     }
713 #endif
714     return engine.take();
715 }
716
717 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
718 {
719     QFontDatabasePrivate *db = privateDb();
720 #ifdef QT_NO_FREETYPE
721     Q_UNUSED(fnt);
722 #else
723     fnt->families = db->addTTFile(QFile::encodeName(fnt->fileName), fnt->data);
724     db->fallbackFamilies += fnt->families;
725 #endif
726     db->reregisterAppFonts = true;
727 }
728
729 bool QFontDatabase::removeApplicationFont(int handle)
730 {
731     QMutexLocker locker(fontDatabaseMutex());
732
733     QFontDatabasePrivate *db = privateDb();
734     if (handle < 0 || handle >= db->applicationFonts.count())
735         return false;
736
737     db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
738
739     db->reregisterAppFonts = true;
740     db->invalidate();
741     return true;
742 }
743
744 bool QFontDatabase::removeAllApplicationFonts()
745 {
746     QMutexLocker locker(fontDatabaseMutex());
747
748     QFontDatabasePrivate *db = privateDb();
749     if (db->applicationFonts.isEmpty())
750         return false;
751
752     db->applicationFonts.clear();
753     db->invalidate();
754     return true;
755 }
756
757 bool QFontDatabase::supportsThreadedFontRendering()
758 {
759     return true;
760 }
761
762 QFontEngine *
763 QFontDatabase::findFont(int script, const QFontPrivate *fp,
764                         const QFontDef &request)
765 {
766     QMutexLocker locker(fontDatabaseMutex());
767
768     const int force_encoding_id = -1;
769
770     if (!privateDb()->count)
771         initializeDb();
772
773     QScopedPointer<QFontEngine> fe;
774     if (fp) {
775         if (fp->rawMode) {
776             fe.reset(loadEngine(script, fp, request, 0, 0, 0, 0));
777
778             // if we fail to load the rawmode font, use a 12pixel box engine instead
779             if (fe.isNull())
780                 fe.reset(new QFontEngineBox(12));
781             return fe.take();
782         }
783
784         QFontCache::Key key(request, script);
785         fe.reset(QFontCache::instance()->findEngine(key));
786         if (! fe.isNull())
787             return fe.take();
788     }
789
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';
796
797     parseFontName(request.family, foundry_name, family_name);
798
799     FM_DEBUG("QFontDatabase::findFont\n"
800              "  request:\n"
801              "    family: %s [%s], script: %d\n"
802              "    weight: %d, style: %d\n"
803              "    stretch: %d\n"
804              "    pixelSize: %g\n"
805              "    pitch: %c",
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);
809
810     if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
811         fe.reset(new QTestFontEngine(request.pixelSize));
812         fe->fontDef = request;
813     }
814
815     if (fe.isNull())
816     {
817         QtFontDesc desc;
818         match(script, request, family_name, foundry_name, force_encoding_id, &desc);
819
820         if (desc.family != 0 && desc.foundry != 0 && desc.style != 0
821             ) {
822             FM_DEBUG("  BEST:\n"
823                      "    family: %s [%s]\n"
824                      "    weight: %d, style: %d\n"
825                      "    stretch: %d\n"
826                      "    pixelSize: %d\n"
827                      "    pitch: %c\n"
828                      "    encoding: %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,
833                      'p', 0
834                 );
835
836             fe.reset(loadEngine(script, fp, request, desc.family, desc.foundry, desc.style, desc.size
837                 ));
838         } else {
839             FM_DEBUG("  NO MATCH FOUND\n");
840         }
841         if (! fe.isNull())
842             initFontDef(desc, request, &fe->fontDef);
843     }
844
845 #ifndef QT_NO_FREETYPE
846     if (! fe.isNull()) {
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");
851                 fe.reset(0);
852             }
853         }
854     }
855 #endif
856
857     if (! fe.isNull()) {
858         if (fp) {
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(',')));
863             }
864             QFontCache::Key key(def, script);
865             QFontCache::instance()->insertEngine(key, fe.data());
866         }
867     }
868
869     if (fe.isNull()) {
870         if (!request.family.isEmpty())
871             return 0;
872
873         FM_DEBUG("returning box engine");
874
875         fe.reset(new QFontEngineBox(request.pixelSize));
876
877         if (fp) {
878             QFontCache::Key key(request, script);
879             QFontCache::instance()->insertEngine(key, fe.data());
880         }
881     }
882
883     if (fp && fp->dpi > 0) {
884         fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / fp->dpi));
885     } else {
886         fe->fontDef.pointSize = request.pointSize;
887     }
888
889     return fe.take();
890 }
891
892 void QFontDatabase::load(const QFontPrivate *d, int script)
893 {
894     QFontDef req = d->request;
895
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;
900
901     if (!d->engineData) {
902         QFontCache::Key key(req, script);
903
904         // look for the requested font in the engine data cache
905         d->engineData = QFontCache::instance()->findEngineData(key);
906
907         if (!d->engineData) {
908             // create a new one
909             d->engineData = new QFontEngineData;
910             QT_TRY {
911                 QFontCache::instance()->insertEngineData(key, d->engineData);
912             } QT_CATCH(...) {
913                 delete d->engineData;
914                 d->engineData = 0;
915                 QT_RETHROW;
916             }
917         } else {
918             d->engineData->ref.ref();
919         }
920     }
921
922     // the cached engineData could have already loaded the engine we want
923     if (d->engineData->engines[script]) return;
924
925     //    double scale = 1.0; // ### TODO: fix the scale calculations
926
927     // list of families to try
928     QStringList family_list;
929
930     if (!req.family.isEmpty()) {
931         family_list = req.family.split(QLatin1Char(','));
932
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;
939
940         // append the default fallback font for the specified script
941         // family_list << ... ; ###########
942
943         // add the default family
944         QString defaultFamily = QApplication::font().family();
945         if (! family_list.contains(defaultFamily))
946             family_list << defaultFamily;
947
948         // add QFont::defaultFamily() to the list, for compatibility with
949         // previous versions
950         family_list << QApplication::font().defaultFamily();
951     }
952
953     // null family means find the first font matching the specified script
954     family_list << QString();
955
956     // load the font
957     QFontEngine *engine = 0;
958     QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
959     for (; !engine && it != end; ++it) {
960         req.family = *it;
961
962         engine = QFontDatabase::findFont(script, d, req);
963         if (engine && (engine->type()==QFontEngine::Box) && !req.family.isEmpty())
964             engine = 0;
965     }
966
967     engine->ref.ref();
968     d->engineData->engines[script] = engine;
969 }
970
971
972 QT_END_NAMESPACE