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