1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 #ifdef Q_OS_QNX
79 // ### using QFontEngineQPF leads to artifacts on QNX
80 #  define QT_NO_QWS_SHARE_FONTS
81 #endif
82 
83 QT_BEGIN_NAMESPACE
84 
85 #ifndef QT_NO_LIBRARY
86 Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
87     (QFontEngineFactoryInterface_iid, QLatin1String("/fontengines"), Qt::CaseInsensitive))
88 #endif
89 
90 const quint8 DatabaseVersion = 4;
91 
92 // QFontDatabasePrivate::addFont() went into qfontdatabase.cpp
93 
94 #ifndef QT_NO_QWS_QPF2
addQPF2File(const QByteArray & file)95 void QFontDatabasePrivate::addQPF2File(const QByteArray &file)
96 {
97 #ifndef QT_FONTS_ARE_RESOURCES
98     struct stat st;
99     if (stat(file.constData(), &st))
100         return;
101     int f = QT_OPEN(file, O_RDONLY, 0);
102     if (f < 0)
103         return;
104     const uchar *data = (const uchar *)mmap(0, st.st_size, PROT_READ, MAP_SHARED, f, 0);
105     const int dataSize = st.st_size;
106 #else
107     QResource res(QLatin1String(file.constData()));
108     const uchar *data = res.data();
109     const int dataSize = res.size();
110     //qDebug() << "addQPF2File" << file << data;
111 #endif
112     if (data && data != (const uchar *)MAP_FAILED) {
113         if (QFontEngineQPF::verifyHeader(data, dataSize)) {
114             QString fontName = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_FontName).toString();
115             int pixelSize = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_PixelSize).toInt();
116             QVariant weight = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_Weight);
117             QVariant style = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_Style);
118             QByteArray writingSystemBits = QFontEngineQPF::extractHeaderField(data, QFontEngineQPF::Tag_WritingSystems).toByteArray();
119 
120             if (!fontName.isEmpty() && pixelSize) {
121                 int fontWeight = 50;
122                 if (weight.type() == QVariant::Int || weight.type() == QVariant::UInt)
123                     fontWeight = weight.toInt();
124 
125                 bool italic = static_cast<QFont::Style>(style.toInt()) & QFont::StyleItalic;
126 
127                 QList<QFontDatabase::WritingSystem> writingSystems;
128                 for (int i = 0; i < writingSystemBits.count(); ++i) {
129                     uchar currentByte = writingSystemBits.at(i);
130                     for (int j = 0; j < 8; ++j) {
131                         if (currentByte & 1)
132                             writingSystems << QFontDatabase::WritingSystem(i * 8 + j);
133                         currentByte >>= 1;
134                     }
135                 }
136 
137                 addFont(fontName, /*foundry*/ "prerendered", fontWeight, italic,
138                         pixelSize, file, /*fileIndex*/ 0,
139                         /*antialiased*/ true, writingSystems);
140             }
141         } else {
142             qDebug() << "header verification of QPF2 font" << file << "failed. maybe it is corrupt?";
143         }
144 #ifndef QT_FONTS_ARE_RESOURCES
145         munmap((void *)data, st.st_size);
146 #endif
147     }
148 #ifndef QT_FONTS_ARE_RESOURCES
149     QT_CLOSE(f);
150 #endif
151 }
152 #endif // QT_NO_QWS_QPF2
153 
154 // QFontDatabasePrivate::addTTFile() went into qfontdatabase.cpp
155 
156 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
157 
158 extern QString qws_fontCacheDir();
159 
160 #ifndef QT_FONTS_ARE_RESOURCES
loadFromCache(const QString & fontPath)161 bool QFontDatabasePrivate::loadFromCache(const QString &fontPath)
162 {
163 #ifdef Q_WS_QWS
164     const bool weAreTheServer = QWSServer::instance();
165 #else
166     const bool weAreTheServer = true; // assume single-process
167 #endif
168 
169     QString fontDirFile = fontPath + QLatin1String("/fontdir");
170 
171     QFile binaryDb(qws_fontCacheDir() + QLatin1String("/fontdb"));
172 
173     if (weAreTheServer) {
174         QDateTime dbTimeStamp = QFileInfo(binaryDb.fileName()).lastModified();
175 
176         QDateTime fontPathTimeStamp = QFileInfo(fontPath).lastModified();
177         if (dbTimeStamp < fontPathTimeStamp)
178             return false; // let the caller create the cache
179 
180         if (QFile::exists(fontDirFile)) {
181             QDateTime fontDirTimeStamp = QFileInfo(fontDirFile).lastModified();
182             if (dbTimeStamp < fontDirTimeStamp)
183                 return false;
184         }
185     }
186 
187     if (!binaryDb.open(QIODevice::ReadOnly)) {
188         if (weAreTheServer)
189             return false; // let the caller create the cache
190         qFatal("QFontDatabase::loadFromCache: Could not open font database cache!");
191     }
192 
193     QDataStream stream(&binaryDb);
194     quint8 version = 0;
195     quint8 dataStreamVersion = 0;
196     stream >> version >> dataStreamVersion;
197     if (version != DatabaseVersion || dataStreamVersion != stream.version()) {
198         if (weAreTheServer)
199             return false; // let the caller create the cache
200         qFatal("QFontDatabase::loadFromCache: Wrong version of the font database cache detected. Found %d/%d expected %d/%d",
201                version, dataStreamVersion, DatabaseVersion, stream.version());
202     }
203 
204     QString originalFontPath;
205     stream >> originalFontPath;
206     if (originalFontPath != fontPath) {
207         if (weAreTheServer)
208             return false; // let the caller create the cache
209         qFatal("QFontDatabase::loadFromCache: Font path doesn't match. Found %s in database, expected %s", qPrintable(originalFontPath), qPrintable(fontPath));
210     }
211 
212     QString familyname;
213     stream >> familyname;
214     //qDebug() << "populating database from" << binaryDb.fileName();
215     while (!familyname.isEmpty() && !stream.atEnd()) {
216         QString foundryname;
217         int weight;
218         quint8 italic;
219         int pixelSize;
220         QByteArray file;
221         int fileIndex;
222         quint8 antialiased;
223         quint8 writingSystemCount;
224 
225         QList<QFontDatabase::WritingSystem> writingSystems;
226 
227         stream >> foundryname >> weight >> italic >> pixelSize
228                >> file >> fileIndex >> antialiased >> writingSystemCount;
229 
230         for (quint8 i = 0; i < writingSystemCount; ++i) {
231             quint8 ws;
232             stream >> ws;
233             writingSystems.append(QFontDatabase::WritingSystem(ws));
234         }
235 
236         addFont(familyname, foundryname.toLatin1().constData(), weight, italic, pixelSize, file, fileIndex, antialiased,
237                 writingSystems);
238 
239         stream >> familyname;
240     }
241 
242     stream >> fallbackFamilies;
243     //qDebug() << "fallback families from cache:" << fallbackFamilies;
244     return true;
245 }
246 #endif // QT_FONTS_ARE_RESOURCES
247 
248 /*!
249     \internal
250 */
251 
qwsFontPath()252 static QString qwsFontPath()
253 {
254     QString fontpath = QString::fromLocal8Bit(qgetenv("QT_QWS_FONTDIR"));
255     if (fontpath.isEmpty()) {
256 #ifdef QT_FONTS_ARE_RESOURCES
257         fontpath = QLatin1String(":/qt/fonts");
258 #else
259 #ifndef QT_NO_SETTINGS
260         fontpath = QLibraryInfo::location(QLibraryInfo::LibrariesPath);
261         fontpath += QLatin1String("/fonts");
262 #else
263         fontpath = QLatin1String("/lib/fonts");
264 #endif
265 #endif //QT_FONTS_ARE_RESOURCES
266     }
267 
268     return fontpath;
269 }
270 
271 #if defined(QFONTDATABASE_DEBUG) && defined(QT_FONTS_ARE_RESOURCES)
272 class FriendlyResource : public QResource
273 {
274 public:
isDir() const275     bool isDir () const { return QResource::isDir(); }
isFile() const276     bool isFile () const { return QResource::isFile(); }
children() const277     QStringList children () const { return QResource::children(); }
278 };
279 #endif
280 /*!
281     \internal
282 */
initializeDb()283 static void initializeDb()
284 {
285     QFontDatabasePrivate *db = privateDb();
286     if (!db || db->count)
287         return;
288 
289     QString fontpath = qwsFontPath();
290 #ifndef QT_FONTS_ARE_RESOURCES
291     QString fontDirFile = fontpath + QLatin1String("/fontdir");
292 
293     if(!QFile::exists(fontpath)) {
294         qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
295                fontpath.toLocal8Bit().constData());
296     }
297 
298     const bool loaded = db->loadFromCache(fontpath);
299 
300     if (db->reregisterAppFonts) {
301         db->reregisterAppFonts = false;
302         for (int i = 0; i < db->applicationFonts.count(); ++i)
303             if (!db->applicationFonts.at(i).families.isEmpty()) {
304                 registerFont(&db->applicationFonts[i]);
305             }
306     }
307 
308     if (loaded)
309         return;
310 
311     QString dbFileName = qws_fontCacheDir() + QLatin1String("/fontdb");
312 
313     QFile binaryDb(dbFileName + QLatin1String(".tmp"));
314     binaryDb.open(QIODevice::WriteOnly | QIODevice::Truncate);
315     db->stream = new QDataStream(&binaryDb);
316     *db->stream << DatabaseVersion << quint8(db->stream->version()) << fontpath;
317 //    qDebug() << "creating binary database at" << binaryDb.fileName();
318 
319     // Load in font definition file
320     FILE* fontdef=fopen(fontDirFile.toLocal8Bit().constData(),"r");
321     if (fontdef) {
322         char buf[200]="";
323         char name[200]="";
324         char render[200]="";
325         char file[200]="";
326         char isitalic[10]="";
327         char flags[10]="";
328         do {
329             fgets(buf,200,fontdef);
330             if (buf[0] != '#') {
331                 int weight=50;
332                 int size=0;
333                 sscanf(buf,"%s %s %s %s %d %d %s",name,file,render,isitalic,&weight,&size,flags);
334                 QString filename;
335                 if (file[0] != '/')
336                     filename.append(fontpath).append(QLatin1Char('/'));
337                 filename += QLatin1String(file);
338                 bool italic = isitalic[0] == 'y';
339                 bool smooth = QByteArray(flags).contains('s');
340                 if (file[0] && QFile::exists(filename))
341                     db->addFont(QString::fromUtf8(name), /*foundry*/"", weight, italic, size/10, QFile::encodeName(filename), /*fileIndex*/ 0, smooth);
342             }
343         } while (!feof(fontdef));
344         fclose(fontdef);
345     }
346 
347 
348     QDir dir(fontpath, QLatin1String("*.qpf"));
349     for (int i=0; i<int(dir.count()); i++) {
350         int u0 = dir[i].indexOf(QLatin1Char('_'));
351         int u1 = dir[i].indexOf(QLatin1Char('_'), u0+1);
352         int u2 = dir[i].indexOf(QLatin1Char('_'), u1+1);
353         int u3 = dir[i].indexOf(QLatin1Char('.'), u1+1);
354         if (u2 < 0) u2 = u3;
355 
356         QString familyname = dir[i].left(u0);
357         int pixelSize = dir[i].mid(u0+1,u1-u0-1).toInt()/10;
358         bool italic = dir[i].mid(u2-1,1) == QLatin1String("i");
359         int weight = dir[i].mid(u1+1,u2-u1-1-(italic?1:0)).toInt();
360 
361         db->addFont(familyname, /*foundry*/ "qt", weight, italic, pixelSize, QFile::encodeName(dir.absoluteFilePath(dir[i])),
362                     /*fileIndex*/ 0, /*antialiased*/ true);
363     }
364 
365 #ifndef QT_NO_FREETYPE
366     dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
367                        << QLatin1String("*.ttc") << QLatin1String("*.pfa")
368                        << QLatin1String("*.pfb"));
369     dir.refresh();
370     for (int i = 0; i < int(dir.count()); ++i) {
371         const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
372 //        qDebug() << "looking at" << file;
373         db->addTTFile(file);
374     }
375 #endif
376 
377 #ifndef QT_NO_QWS_QPF2
378     dir.setNameFilters(QStringList() << QLatin1String("*.qpf2"));
379     dir.refresh();
380     for (int i = 0; i < int(dir.count()); ++i) {
381         const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
382 //        qDebug() << "looking at" << file;
383         db->addQPF2File(file);
384     }
385 #endif
386 
387 #else //QT_FONTS_ARE_RESOURCES
388 #ifdef QFONTDATABASE_DEBUG
389     {
390         QResource fontdir(fontpath);
391         FriendlyResource *fr = static_cast<FriendlyResource*>(&fontdir);
392         qDebug() << "fontdir" << fr->isValid() << fr->isDir() << fr->children();
393 
394     }
395 #endif
396 #ifndef QT_NO_QWS_QPF2
397     QDir dir(fontpath, QLatin1String("*.qpf2"));
398     for (int i = 0; i < int(dir.count()); ++i) {
399         const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
400         //qDebug() << "looking at" << file;
401         db->addQPF2File(file);
402     }
403 #endif
404 #endif //QT_FONTS_ARE_RESOURCES
405 
406 
407 #ifdef QFONTDATABASE_DEBUG
408     // print the database
409     for (int f = 0; f < db->count; f++) {
410         QtFontFamily *family = db->families[f];
411         FD_DEBUG("'%s' %s", qPrintable(family->name), (family->fixedPitch ? "fixed" : ""));
412 #if 0
413         for (int i = 0; i < QFont::LastPrivateScript; ++i) {
414             FD_DEBUG("\t%s: %s", qPrintable(QFontDatabase::scriptName((QFont::Script) i)),
415                      ((family->scripts[i] & QtFontFamily::Supported) ? "Supported" :
416                       (family->scripts[i] & QtFontFamily::UnSupported) == QtFontFamily::UnSupported ?
417                       "UnSupported" : "Unknown"));
418         }
419 #endif
420 
421         for (int fd = 0; fd < family->count; fd++) {
422             QtFontFoundry *foundry = family->foundries[fd];
423             FD_DEBUG("\t\t'%s'", qPrintable(foundry->name));
424             for (int s = 0; s < foundry->count; s++) {
425                 QtFontStyle *style = foundry->styles[s];
426                 FD_DEBUG("\t\t\tstyle: style=%d weight=%d\n"
427                          "\t\t\tstretch=%d",
428                          style->key.style, style->key.weight,
429                          style->key.stretch);
430                 if (style->smoothScalable)
431                     FD_DEBUG("\t\t\t\tsmooth scalable");
432                 else if (style->bitmapScalable)
433                     FD_DEBUG("\t\t\t\tbitmap scalable");
434                 if (style->pixelSizes) {
435                     FD_DEBUG("\t\t\t\t%d pixel sizes",  style->count);
436                     for (int z = 0; z < style->count; ++z) {
437                         QtFontSize *size = style->pixelSizes + z;
438                         FD_DEBUG("\t\t\t\t  size %5d",
439                                   size->pixelSize);
440                     }
441                 }
442             }
443         }
444     }
445 #endif // QFONTDATABASE_DEBUG
446 
447 #ifndef QT_NO_LIBRARY
448     QStringList pluginFoundries = loader()->keys();
449 //    qDebug() << "plugin foundries:" << pluginFoundries;
450     for (int i = 0; i < pluginFoundries.count(); ++i) {
451         const QString foundry(pluginFoundries.at(i));
452 
453         QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry));
454         if (!factory) {
455             qDebug() << "Could not load plugin for foundry" << foundry;
456             continue;
457         }
458 
459         QList<QFontEngineInfo> fonts = factory->availableFontEngines();
460         for (int i = 0; i < fonts.count(); ++i) {
461             QFontEngineInfo info = fonts.at(i);
462 
463             int weight = info.weight();
464             if (weight <= 0)
465                 weight = QFont::Normal;
466 
467             db->addFont(info.family(), foundry.toLatin1().constData(),
468                         weight, info.style() != QFont::StyleNormal,
469                         qRound(info.pixelSize()), /*file*/QByteArray(),
470                         /*fileIndex*/0, /*antiAliased*/true,
471                         info.writingSystems());
472         }
473     }
474 #endif
475 
476 #ifndef QT_FONTS_ARE_RESOURCES
477     // the empty string/familyname signifies the end of the font list.
478     *db->stream << QString();
479 #endif
480     {
481         bool coveredWritingSystems[QFontDatabase::WritingSystemsCount] = { 0 };
482 
483         db->fallbackFamilies.clear();
484 
485         for (int i = 0; i < db->count; ++i) {
486             QtFontFamily *family = db->families[i];
487             bool add = false;
488             if (family->count == 0)
489                 continue;
490             if (family->bogusWritingSystems)
491                 continue;
492             for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
493                 if (coveredWritingSystems[ws])
494                     continue;
495                 if (family->writingSystems[ws] & QtFontFamily::Supported) {
496                     coveredWritingSystems[ws] = true;
497                     add = true;
498                 }
499             }
500             if (add)
501                 db->fallbackFamilies << family->name;
502         }
503         //qDebug() << "fallbacks on the server:" << db->fallbackFamilies;
504 #ifndef QT_FONTS_ARE_RESOURCES
505         *db->stream << db->fallbackFamilies;
506 #endif
507     }
508 #ifndef QT_FONTS_ARE_RESOURCES
509     delete db->stream;
510     db->stream = 0;
511     QFile::remove(dbFileName);
512     binaryDb.rename(dbFileName);
513 #endif
514 }
515 
516 // called from qwindowsystem_qws.cpp
qt_qws_init_fontdb()517 void qt_qws_init_fontdb()
518 {
519     initializeDb();
520 }
521 
522 #ifndef QT_NO_SETTINGS
523 // called from qapplication_qws.cpp
qt_applyFontDatabaseSettings(const QSettings & settings)524 void qt_applyFontDatabaseSettings(const QSettings &settings)
525 {
526     initializeDb();
527     QFontDatabasePrivate *db = privateDb();
528     for (int i = 0; i < db->count; ++i) {
529         QtFontFamily *family = db->families[i];
530         if (settings.contains(family->name))
531             family->fallbackFamilies = settings.value(family->name).toStringList();
532     }
533 
534     if (settings.contains(QLatin1String("Global Fallbacks")))
535         db->fallbackFamilies = settings.value(QLatin1String("Global Fallbacks")).toStringList();
536 }
537 #endif // QT_NO_SETTINGS
538 
load(const QString &=QString (),int=-1)539 static inline void load(const QString & = QString(), int = -1)
540 {
541     initializeDb();
542 }
543 
544 #ifndef QT_NO_FREETYPE
545 
546 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
547 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
548 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
549 #else
550 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
551 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
552 #endif
553 
554 #endif // QT_NO_FREETYPE
555 
556 static
loadSingleEngine(int script,const QFontPrivate * fp,const QFontDef & request,QtFontFamily * family,QtFontFoundry * foundry,QtFontStyle * style,QtFontSize * size)557 QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp,
558                               const QFontDef &request,
559                               QtFontFamily *family, QtFontFoundry *foundry,
560                               QtFontStyle *style, QtFontSize *size)
561 {
562     Q_UNUSED(script);
563     Q_UNUSED(fp);
564 #ifdef QT_NO_FREETYPE
565     Q_UNUSED(foundry);
566 #endif
567 #ifdef QT_NO_QWS_QPF
568     Q_UNUSED(family);
569 #endif
570     Q_ASSERT(size);
571 
572     int pixelSize = size->pixelSize;
573     if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE))
574         pixelSize = request.pixelSize;
575 
576 #ifndef QT_NO_QWS_QPF2
577     if (foundry->name == QLatin1String("prerendered")) {
578 #ifdef QT_FONTS_ARE_RESOURCES
579         QResource res(QLatin1String(size->fileName.constData()));
580         if (res.isValid()) {
581             QFontEngineQPF *fe = new QFontEngineQPF(request, res.data(), res.size());
582             if (fe->isValid())
583                 return fe;
584             delete fe;
585             qDebug() << "fontengine is not valid! " << size->fileName;
586         } else {
587             qDebug() << "Resource not valid" << size->fileName;
588         }
589 #else
590         int f = ::open(size->fileName, O_RDONLY, 0);
591         if (f >= 0) {
592             QFontEngineQPF *fe = new QFontEngineQPF(request, f);
593             if (fe->isValid())
594                 return fe;
595             delete fe; // will close f
596             qDebug() << "fontengine is not valid!";
597         }
598 #endif
599     } else
600 #endif
601     if ( foundry->name != QLatin1String("qt") ) { ///#### is this the best way????
602         QString file = QFile::decodeName(size->fileName);
603 
604         QFontDef def = request;
605         def.pixelSize = pixelSize;
606 
607 #ifdef QT_NO_QWS_SHARE_FONTS
608         bool shareFonts = false;
609 #else
610         static bool dontShareFonts = !qgetenv("QWS_NO_SHARE_FONTS").isEmpty();
611         bool shareFonts = !dontShareFonts;
612 #endif
613 
614         QScopedPointer<QFontEngine> engine;
615 
616 #ifndef QT_NO_LIBRARY
617         QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry->name));
618         if (factory) {
619             QFontEngineInfo info;
620             info.setFamily(request.family);
621             info.setPixelSize(request.pixelSize);
622             info.setStyle(QFont::Style(request.style));
623             info.setWeight(request.weight);
624             // #### antialiased
625 
626             QAbstractFontEngine *customEngine = factory->create(info);
627             if (customEngine) {
628                 engine.reset(new QProxyFontEngine(customEngine, def));
629 
630                 if (shareFonts) {
631                     QVariant hint = customEngine->fontProperty(QAbstractFontEngine::CacheGlyphsHint);
632                     if (hint.isValid())
633                         shareFonts = hint.toBool();
634                     else
635                         shareFonts = (pixelSize < 64);
636                 }
637             }
638         }
639 #endif // QT_NO_LIBRARY
640         if ((engine.isNull() && !file.isEmpty() && QFile::exists(file)) || privateDb()->isApplicationFont(file)) {
641             QFontEngine::FaceId faceId;
642             faceId.filename = file.toLocal8Bit();
643             faceId.index = size->fileIndex;
644 
645 #ifndef QT_NO_FREETYPE
646 
647             QScopedPointer<QFontEngineFT> fte(new QFontEngineFT(def));
648             bool antialias = style->antialiased && !(request.styleStrategy & QFont::NoAntialias);
649             if (fte->init(faceId, antialias,
650                           antialias ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono)) {
651 #ifdef QT_NO_QWS_QPF2
652                 return fte.take();
653 #else
654                 // try to distinguish between bdf and ttf fonts we can pre-render
655                 // and don't try to share outline fonts
656                 shareFonts = shareFonts
657                              && !fte->defaultGlyphs()->outline_drawing
658                              && !fte->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd')).isEmpty();
659                 engine.reset(fte.take());
660 #endif
661             }
662 #endif // QT_NO_FREETYPE
663         }
664         if (!engine.isNull()) {
665 #if !defined(QT_NO_QWS_QPF2) && !defined(QT_FONTS_ARE_RESOURCES)
666             if (shareFonts) {
667                 QScopedPointer<QFontEngineQPF> fe(new QFontEngineQPF(def, -1, engine.data()));
668                 engine.take();
669                 if (fe->isValid())
670                     return fe.take();
671                 qWarning("Initializing QFontEngineQPF failed for %s", qPrintable(file));
672                 engine.reset(fe->takeRenderingEngine());
673             }
674 #endif
675             return engine.take();
676         }
677     } else
678     {
679 #ifndef QT_NO_QWS_QPF
680         QString fn = qwsFontPath();
681         fn += QLatin1Char('/');
682         fn += family->name.toLower()
683               + QLatin1Char('_') + QString::number(pixelSize*10)
684               + QLatin1Char('_') + QString::number(style->key.weight)
685               + (style->key.style == QFont::StyleItalic ?
686                  QLatin1String("i.qpf") : QLatin1String(".qpf"));
687         //###rotation ###
688 
689         QFontEngine *fe = new QFontEngineQPF1(request, fn);
690         return fe;
691 #endif // QT_NO_QWS_QPF
692     }
693     return new QFontEngineBox(pixelSize);
694 }
695 
696 static
loadEngine(int script,const QFontPrivate * fp,const QFontDef & request,QtFontFamily * family,QtFontFoundry * foundry,QtFontStyle * style,QtFontSize * size)697 QFontEngine *loadEngine(int script, const QFontPrivate *fp,
698                         const QFontDef &request,
699                         QtFontFamily *family, QtFontFoundry *foundry,
700                         QtFontStyle *style, QtFontSize *size)
701 {
702     QScopedPointer<QFontEngine> engine(loadSingleEngine(script, fp, request, family, foundry,
703                                        style, size));
704 #ifndef QT_NO_QWS_QPF
705     if (!engine.isNull()
706         && script == QUnicodeTables::Common
707         && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
708 
709         QStringList fallbacks = privateDb()->fallbackFamilies;
710 
711         if (family && !family->fallbackFamilies.isEmpty())
712             fallbacks = family->fallbackFamilies;
713 
714         QFontEngine *fe = new QFontEngineMultiQWS(engine.data(), script, fallbacks);
715         engine.take();
716         engine.reset(fe);
717     }
718 #endif
719     return engine.take();
720 }
721 
registerFont(QFontDatabasePrivate::ApplicationFont * fnt)722 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
723 {
724     QFontDatabasePrivate *db = privateDb();
725 #ifdef QT_NO_FREETYPE
726     Q_UNUSED(fnt);
727 #else
728     fnt->families = db->addTTFile(QFile::encodeName(fnt->fileName), fnt->data);
729     db->fallbackFamilies += fnt->families;
730 #endif
731     db->reregisterAppFonts = true;
732 }
733 
removeApplicationFont(int handle)734 bool QFontDatabase::removeApplicationFont(int handle)
735 {
736     QMutexLocker locker(fontDatabaseMutex());
737 
738     QFontDatabasePrivate *db = privateDb();
739     if (handle < 0 || handle >= db->applicationFonts.count())
740         return false;
741 
742     db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
743 
744     db->reregisterAppFonts = true;
745     db->invalidate();
746     return true;
747 }
748 
removeAllApplicationFonts()749 bool QFontDatabase::removeAllApplicationFonts()
750 {
751     QMutexLocker locker(fontDatabaseMutex());
752 
753     QFontDatabasePrivate *db = privateDb();
754     if (db->applicationFonts.isEmpty())
755         return false;
756 
757     db->applicationFonts.clear();
758     db->invalidate();
759     return true;
760 }
761 
supportsThreadedFontRendering()762 bool QFontDatabase::supportsThreadedFontRendering()
763 {
764     return true;
765 }
766 
767 QFontEngine *
findFont(int script,const QFontPrivate * fp,const QFontDef & request)768 QFontDatabase::findFont(int script, const QFontPrivate *fp,
769                         const QFontDef &request)
770 {
771     QMutexLocker locker(fontDatabaseMutex());
772 
773     const int force_encoding_id = -1;
774 
775     if (!privateDb()->count)
776         initializeDb();
777 
778     QScopedPointer<QFontEngine> fe;
779     if (fp) {
780         if (fp->rawMode) {
781             fe.reset(loadEngine(script, fp, request, 0, 0, 0, 0));
782 
783             // if we fail to load the rawmode font, use a 12pixel box engine instead
784             if (fe.isNull())
785                 fe.reset(new QFontEngineBox(12));
786             return fe.take();
787         }
788 
789         QFontCache::Key key(request, script);
790         fe.reset(QFontCache::instance()->findEngine(key));
791         if (! fe.isNull())
792             return fe.take();
793     }
794 
795     QString family_name, foundry_name;
796     QtFontStyle::Key styleKey;
797     styleKey.style = request.style;
798     styleKey.weight = request.weight;
799     styleKey.stretch = request.stretch;
800     char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
801 
802     parseFontName(request.family, foundry_name, family_name);
803 
804     FM_DEBUG("QFontDatabase::findFont\n"
805              "  request:\n"
806              "    family: %s [%s], script: %d\n"
807              "    weight: %d, style: %d\n"
808              "    stretch: %d\n"
809              "    pixelSize: %g\n"
810              "    pitch: %c",
811              family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
812              foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
813              script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
814 
815     if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
816         fe.reset(new QTestFontEngine(request.pixelSize));
817         fe->fontDef = request;
818     }
819 
820     if (fe.isNull())
821     {
822         QtFontDesc desc;
823         match(script, request, family_name, foundry_name, force_encoding_id, &desc);
824 
825         if (desc.family != 0 && desc.foundry != 0 && desc.style != 0
826             ) {
827             FM_DEBUG("  BEST:\n"
828                      "    family: %s [%s]\n"
829                      "    weight: %d, style: %d\n"
830                      "    stretch: %d\n"
831                      "    pixelSize: %d\n"
832                      "    pitch: %c\n"
833                      "    encoding: %d\n",
834                      desc.family->name.toLatin1().constData(),
835                      desc.foundry->name.isEmpty() ? "-- none --" : desc.foundry->name.toLatin1().constData(),
836                      desc.style->key.weight, desc.style->key.style,
837                      desc.style->key.stretch, desc.size ? desc.size->pixelSize : 0xffff,
838                      'p', 0
839                 );
840 
841             fe.reset(loadEngine(script, fp, request, desc.family, desc.foundry, desc.style, desc.size
842                 ));
843         } else {
844             FM_DEBUG("  NO MATCH FOUND\n");
845         }
846         if (! fe.isNull())
847             initFontDef(desc, request, &fe->fontDef);
848     }
849 
850 #ifndef QT_NO_FREETYPE
851     if (! fe.isNull()) {
852         if (scriptRequiresOpenType(script) && fe->type() == QFontEngine::Freetype) {
853             HB_Face hbFace = static_cast<QFontEngineFT *>(fe.data())->harfbuzzFace();
854             if (!hbFace || !hbFace->supported_scripts[script]) {
855                 FM_DEBUG("  OpenType support missing for script\n");
856                 fe.reset(0);
857             }
858         }
859     }
860 #endif
861 
862     if (! fe.isNull()) {
863         if (fp) {
864             QFontDef def = request;
865             if (def.family.isEmpty()) {
866                 def.family = fp->request.family;
867                 def.family = def.family.left(def.family.indexOf(QLatin1Char(',')));
868             }
869             QFontCache::Key key(def, script);
870             QFontCache::instance()->insertEngine(key, fe.data());
871         }
872     }
873 
874     if (fe.isNull()) {
875         if (!request.family.isEmpty())
876             return 0;
877 
878         FM_DEBUG("returning box engine");
879 
880         fe.reset(new QFontEngineBox(request.pixelSize));
881 
882         if (fp) {
883             QFontCache::Key key(request, script);
884             QFontCache::instance()->insertEngine(key, fe.data());
885         }
886     }
887 
888     if (fp && fp->dpi > 0) {
889         fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / fp->dpi));
890     } else {
891         fe->fontDef.pointSize = request.pointSize;
892     }
893 
894     return fe.take();
895 }
896 
load(const QFontPrivate * d,int script)897 void QFontDatabase::load(const QFontPrivate *d, int script)
898 {
899     QFontDef req = d->request;
900 
901     if (req.pixelSize == -1)
902         req.pixelSize = qRound(req.pointSize*d->dpi/72);
903     if (req.pointSize < 0)
904         req.pointSize = req.pixelSize*72.0/d->dpi;
905 
906     if (!d->engineData) {
907         QFontCache::Key key(req, script);
908 
909         // look for the requested font in the engine data cache
910         d->engineData = QFontCache::instance()->findEngineData(key);
911 
912         if (!d->engineData) {
913             // create a new one
914             d->engineData = new QFontEngineData;
915             QT_TRY {
916                 QFontCache::instance()->insertEngineData(key, d->engineData);
917             } QT_CATCH(...) {
918                 delete d->engineData;
919                 d->engineData = 0;
920                 QT_RETHROW;
921             }
922         } else {
923             d->engineData->ref.ref();
924         }
925     }
926 
927     // the cached engineData could have already loaded the engine we want
928     if (d->engineData->engines[script]) return;
929 
930     //    double scale = 1.0; // ### TODO: fix the scale calculations
931 
932     // list of families to try
933     QStringList family_list;
934 
935     if (!req.family.isEmpty()) {
936         family_list = req.family.split(QLatin1Char(','));
937 
938         // append the substitute list for each family in family_list
939         QStringList subs_list;
940         QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
941         for (; it != end; ++it)
942             subs_list += QFont::substitutes(*it);
943         family_list += subs_list;
944 
945         // append the default fallback font for the specified script
946         // family_list << ... ; ###########
947 
948         // add the default family
949         QString defaultFamily = QApplication::font().family();
950         if (! family_list.contains(defaultFamily))
951             family_list << defaultFamily;
952 
953         // add QFont::defaultFamily() to the list, for compatibility with
954         // previous versions
955         family_list << QApplication::font().defaultFamily();
956     }
957 
958     // null family means find the first font matching the specified script
959     family_list << QString();
960 
961     // load the font
962     QFontEngine *engine = 0;
963     QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
964     for (; !engine && it != end; ++it) {
965         req.family = *it;
966 
967         engine = QFontDatabase::findFont(script, d, req);
968         if (engine && (engine->type()==QFontEngine::Box) && !req.family.isEmpty())
969             engine = 0;
970     }
971 
972     engine->ref.ref();
973     d->engineData->engines[script] = engine;
974 }
975 
976 
977 QT_END_NAMESPACE
978