src/gui/text/qfontengine_qpf.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
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 "qfontengine_qpf_p.h"
       
    43 
       
    44 #include "private/qpaintengine_raster_p.h"
       
    45 #include <QtCore/qlibraryinfo.h>
       
    46 #include <QtCore/qfileinfo.h>
       
    47 
       
    48 #include <QtCore/qfile.h>
       
    49 #include <QtCore/qdir.h>
       
    50 #include <QtCore/qbuffer.h>
       
    51 #if !defined(QT_NO_FREETYPE)
       
    52 #include "private/qfontengine_ft_p.h"
       
    53 #endif
       
    54 #include "private/qcore_unix_p.h" // overrides QT_OPEN
       
    55 
       
    56 // for mmap
       
    57 #include <stdlib.h>
       
    58 #include <unistd.h>
       
    59 #include <sys/types.h>
       
    60 #include <sys/stat.h>
       
    61 #include <sys/mman.h>
       
    62 #include <fcntl.h>
       
    63 #include <errno.h>
       
    64 
       
    65 QT_BEGIN_NAMESPACE
       
    66 
       
    67 #ifndef QT_NO_QWS_QPF2
       
    68 
       
    69 #include "qpfutil.cpp"
       
    70 
       
    71 QT_BEGIN_INCLUDE_NAMESPACE
       
    72 
       
    73 #if defined(Q_WS_QWS)
       
    74 #   include "private/qwscommand_qws_p.h"
       
    75 #   include "qwsdisplay_qws.h"
       
    76 #   include "qabstractfontengine_p.h"
       
    77 #endif
       
    78 #include "qplatformdefs.h"
       
    79 QT_END_INCLUDE_NAMESPACE
       
    80 
       
    81 //#define DEBUG_HEADER
       
    82 //#define DEBUG_FONTENGINE
       
    83 
       
    84 #if defined(DEBUG_HEADER)
       
    85 # define DEBUG_VERIFY qDebug
       
    86 #else
       
    87 # define DEBUG_VERIFY if (0) qDebug
       
    88 #endif
       
    89 
       
    90 #define READ_VERIFY(type, variable) \
       
    91     if (tagPtr + sizeof(type) > endPtr) { \
       
    92         DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \
       
    93         return 0; \
       
    94     } \
       
    95     variable = qFromBigEndian<type>(tagPtr); \
       
    96     DEBUG_VERIFY() << "read value" << variable << "of type " #type; \
       
    97     tagPtr += sizeof(type)
       
    98 
       
    99 template <typename T>
       
   100 T readValue(const uchar *&data)
       
   101 {
       
   102     T value = qFromBigEndian<T>(data);
       
   103     data += sizeof(T);
       
   104     return value;
       
   105 }
       
   106 
       
   107 #define VERIFY(condition) \
       
   108     if (!(condition)) { \
       
   109         DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \
       
   110         return 0; \
       
   111     }
       
   112 
       
   113 #define VERIFY_TAG(condition) \
       
   114     if (!(condition)) { \
       
   115         DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \
       
   116         return 0; \
       
   117     }
       
   118 
       
   119 static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr)
       
   120 {
       
   121     quint16 tag, length;
       
   122     READ_VERIFY(quint16, tag);
       
   123     READ_VERIFY(quint16, length);
       
   124     if (tag == QFontEngineQPF::Tag_EndOfHeader)
       
   125         return endPtr;
       
   126     if (tag < QFontEngineQPF::NumTags) {
       
   127         switch (tagTypes[tag]) {
       
   128             case QFontEngineQPF::BitFieldType:
       
   129             case QFontEngineQPF::StringType:
       
   130                 // can't do anything...
       
   131                 break;
       
   132             case QFontEngineQPF::UInt32Type:
       
   133                 VERIFY_TAG(length == sizeof(quint32));
       
   134                 break;
       
   135             case QFontEngineQPF::FixedType:
       
   136                 VERIFY_TAG(length == sizeof(quint32));
       
   137                 break;
       
   138             case QFontEngineQPF::UInt8Type:
       
   139                 VERIFY_TAG(length == sizeof(quint8));
       
   140                 break;
       
   141         }
       
   142 #if defined(DEBUG_HEADER)
       
   143         if (length == 1)
       
   144             qDebug() << "tag data" << hex << *tagPtr;
       
   145         else if (length == 4)
       
   146             qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
       
   147 #endif
       
   148     }
       
   149     return tagPtr + length;
       
   150 }
       
   151 
       
   152 const QFontEngineQPF::Glyph *QFontEngineQPF::findGlyph(glyph_t g) const
       
   153 {
       
   154     if (!g || g >= glyphMapEntries)
       
   155         return 0;
       
   156     const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
       
   157     quint32 glyphPos = qFromBigEndian<quint32>(gmapPtr[g]);
       
   158     if (glyphPos > glyphDataSize) {
       
   159         if (glyphPos == 0xffffffff)
       
   160             return 0;
       
   161 #if defined(DEBUG_FONTENGINE)
       
   162         qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
       
   163 #endif
       
   164 #if !defined(QT_NO_FREETYPE) && !defined(QT_FONTS_ARE_RESOURCES)
       
   165         const_cast<QFontEngineQPF *>(this)->remapFontData();
       
   166 #endif
       
   167         if (glyphPos > glyphDataSize)
       
   168             return 0;
       
   169     }
       
   170     return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
       
   171 }
       
   172 
       
   173 bool QFontEngineQPF::verifyHeader(const uchar *data, int size)
       
   174 {
       
   175     VERIFY(size >= int(sizeof(Header)));
       
   176     const Header *header = reinterpret_cast<const Header *>(data);
       
   177     if (header->magic[0] != 'Q'
       
   178         || header->magic[1] != 'P'
       
   179         || header->magic[2] != 'F'
       
   180         || header->magic[3] != '2')
       
   181         return false;
       
   182 
       
   183     VERIFY(header->majorVersion <= CurrentMajorVersion);
       
   184     const quint16 dataSize = qFromBigEndian<quint16>(header->dataSize);
       
   185     VERIFY(size >= int(sizeof(Header)) + dataSize);
       
   186 
       
   187     const uchar *tagPtr = data + sizeof(Header);
       
   188     const uchar *tagEndPtr = tagPtr + dataSize;
       
   189     while (tagPtr < tagEndPtr - 3) {
       
   190         tagPtr = verifyTag(tagPtr, tagEndPtr);
       
   191         VERIFY(tagPtr);
       
   192     }
       
   193 
       
   194     VERIFY(tagPtr <= tagEndPtr);
       
   195     return true;
       
   196 }
       
   197 
       
   198 QVariant QFontEngineQPF::extractHeaderField(const uchar *data, HeaderTag requestedTag)
       
   199 {
       
   200     const Header *header = reinterpret_cast<const Header *>(data);
       
   201     const uchar *tagPtr = data + sizeof(Header);
       
   202     const uchar *endPtr = tagPtr + qFromBigEndian<quint16>(header->dataSize);
       
   203     while (tagPtr < endPtr - 3) {
       
   204         quint16 tag = readValue<quint16>(tagPtr);
       
   205         quint16 length = readValue<quint16>(tagPtr);
       
   206         if (tag == requestedTag) {
       
   207             switch (tagTypes[requestedTag]) {
       
   208                 case StringType:
       
   209                     return QVariant(QString::fromUtf8(reinterpret_cast<const char *>(tagPtr), length));
       
   210                 case UInt32Type:
       
   211                     return QVariant(readValue<quint32>(tagPtr));
       
   212                 case UInt8Type:
       
   213                     return QVariant(uint(*tagPtr));
       
   214                 case FixedType:
       
   215                     return QVariant(QFixed::fromFixed(readValue<quint32>(tagPtr)).toReal());
       
   216                 case BitFieldType:
       
   217                     return QVariant(QByteArray(reinterpret_cast<const char *>(tagPtr), length));
       
   218             }
       
   219             return QVariant();
       
   220         } else if (tag == Tag_EndOfHeader) {
       
   221             break;
       
   222         }
       
   223         tagPtr += length;
       
   224     }
       
   225 
       
   226     return QVariant();
       
   227 }
       
   228 
       
   229 #endif // QT_NO_QWS_QPF2
       
   230 
       
   231 QString qws_fontCacheDir()
       
   232 {
       
   233     QString dir;
       
   234 #if defined(Q_WS_QWS)
       
   235     extern QString qws_dataDir();
       
   236     dir = qws_dataDir();
       
   237 #else
       
   238     dir = QDir::tempPath();
       
   239 #endif
       
   240     dir.append(QLatin1String("/fonts/"));
       
   241     QDir qd(dir);
       
   242     if (!qd.exists() && !qd.mkpath(dir))
       
   243         dir = QDir::tempPath();
       
   244     return dir;
       
   245 }
       
   246 
       
   247 #ifndef QT_NO_QWS_QPF2
       
   248 
       
   249 #ifndef QT_FONTS_ARE_RESOURCES
       
   250 QList<QByteArray> QFontEngineQPF::cleanUpAfterClientCrash(const QList<int> &crashedClientIds)
       
   251 {
       
   252     QList<QByteArray> removedFonts;
       
   253     QDir dir(qws_fontCacheDir(), QLatin1String("*.qsf"));
       
   254     for (int i = 0; i < int(dir.count()); ++i) {
       
   255         const QByteArray fileName = QFile::encodeName(dir.absoluteFilePath(dir[i]));
       
   256 
       
   257         int fd = QT_OPEN(fileName.constData(), O_RDONLY, 0);
       
   258         if (fd >= 0) {
       
   259             void *header = ::mmap(0, sizeof(QFontEngineQPF::Header), PROT_READ, MAP_SHARED, fd, 0);
       
   260             if (header && header != MAP_FAILED) {
       
   261                 quint32 lockValue = reinterpret_cast<QFontEngineQPF::Header *>(header)->lock;
       
   262 
       
   263                 if (lockValue && crashedClientIds.contains(lockValue)) {
       
   264                     removedFonts.append(fileName);
       
   265                     QFile::remove(QFile::decodeName(fileName));
       
   266                 }
       
   267 
       
   268                 ::munmap(header, sizeof(QFontEngineQPF::Header));
       
   269             }
       
   270             QT_CLOSE(fd);
       
   271         }
       
   272     }
       
   273     if (!removedFonts.isEmpty())
       
   274         qDebug() << "list of corrupted and removed fonts:" << removedFonts;
       
   275     return removedFonts;
       
   276 }
       
   277 #endif
       
   278 
       
   279 static inline unsigned int getChar(const QChar *str, int &i, const int len)
       
   280 {
       
   281     unsigned int uc = str[i].unicode();
       
   282     if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
       
   283         uint low = str[i+1].unicode();
       
   284        if (low >= 0xdc00 && low < 0xe000) {
       
   285             uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
       
   286             ++i;
       
   287         }
       
   288     }
       
   289     return uc;
       
   290 }
       
   291 #ifdef QT_FONTS_ARE_RESOURCES
       
   292 QFontEngineQPF::QFontEngineQPF(const QFontDef &def, const uchar *bytes, int size)
       
   293     : fd(-1), fontData(bytes), dataSize(size), renderingFontEngine(0)
       
   294 #else
       
   295 QFontEngineQPF::QFontEngineQPF(const QFontDef &def, int fileDescriptor, QFontEngine *fontEngine)
       
   296     : fd(fileDescriptor), fontData(0), dataSize(0), renderingFontEngine(fontEngine)
       
   297 #endif
       
   298 {
       
   299     fontDef = def;
       
   300     cache_cost = 100;
       
   301     freetype = 0;
       
   302     externalCMap = 0;
       
   303     cmapOffset = 0;
       
   304     cmapSize = 0;
       
   305     glyphMapOffset = 0;
       
   306     glyphMapEntries = 0;
       
   307     glyphDataOffset = 0;
       
   308     glyphDataSize = 0;
       
   309     kerning_pairs_loaded = false;
       
   310     readOnly = true;
       
   311 
       
   312 #if defined(DEBUG_FONTENGINE)
       
   313     qDebug() << "QFontEngineQPF::QFontEngineQPF( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
       
   314 #endif
       
   315 
       
   316 #ifndef QT_FONTS_ARE_RESOURCES
       
   317     if (fd < 0) {
       
   318         if (!renderingFontEngine)
       
   319             return;
       
   320 
       
   321         fileName = fontDef.family.toLower() + QLatin1Char('_')
       
   322                    + QString::number(fontDef.pixelSize)
       
   323                    + QLatin1Char('_') + QString::number(fontDef.weight)
       
   324                    + (fontDef.style != QFont::StyleNormal ?
       
   325                       QLatin1String("_italic") : QLatin1String(""))
       
   326                    + QLatin1String(".qsf");
       
   327         fileName.replace(QLatin1Char(' '), QLatin1Char('_'));
       
   328         fileName.prepend(qws_fontCacheDir());
       
   329 
       
   330         encodedFileName = QFile::encodeName(fileName);
       
   331         if (::access(encodedFileName, F_OK) == 0) {
       
   332 #if defined(DEBUG_FONTENGINE)
       
   333             qDebug() << "found existing qpf:" << fileName;
       
   334 #endif
       
   335             if (::access(encodedFileName, W_OK | R_OK) == 0) {
       
   336                 fd = QT_OPEN(encodedFileName, O_RDWR);
       
   337             }
       
   338             // read-write access failed - try read-only access
       
   339             if (fd == -1 && ::access(encodedFileName, R_OK) == 0) {
       
   340                 fd = QT_OPEN(encodedFileName, O_RDONLY);
       
   341                 if (fd == -1) {
       
   342 #if defined(DEBUG_FONTENGINE)
       
   343                     qErrnoWarning("QFontEngineQPF: unable to open %s", encodedName.constData());
       
   344 #endif
       
   345                     return;
       
   346                 }
       
   347             }
       
   348             if (fd == -1) {
       
   349 #if defined(DEBUG_FONTENGINE)
       
   350                 qWarning("QFontEngineQPF: insufficient access rights to %s", encodedName.constData());
       
   351 #endif
       
   352                 return;
       
   353             }
       
   354         } else {
       
   355 #if defined(DEBUG_FONTENGINE)
       
   356             qDebug() << "creating qpf on the fly:" << fileName;
       
   357 #endif
       
   358             if (::access(QFile::encodeName(qws_fontCacheDir()), W_OK) == 0) {
       
   359                 fd = QT_OPEN(encodedFileName, O_RDWR | O_EXCL | O_CREAT, 0644);
       
   360                 if (fd == -1) {
       
   361 #if defined(DEBUG_FONTENGINE)
       
   362                     qErrnoWarning(errno, "QFontEngineQPF: open() failed for %s", encodedName.constData());
       
   363 #endif
       
   364                     return;
       
   365                 }
       
   366 
       
   367                 QBuffer buffer;
       
   368                 buffer.open(QIODevice::ReadWrite);
       
   369                 QPFGenerator generator(&buffer, renderingFontEngine);
       
   370                 generator.generate();
       
   371                 buffer.close();
       
   372                 const QByteArray &data = buffer.data();
       
   373                 if (QT_WRITE(fd, data.constData(), data.size()) == -1) {
       
   374 #if defined(DEBUG_FONTENGINE)
       
   375                     qErrnoWarning(errno, "QFontEngineQPF: write() failed for %s", encodedName.constData());
       
   376 #endif
       
   377                     return;
       
   378                 }
       
   379             } else {
       
   380 #if defined(DEBUG_FONTENGINE)
       
   381                 qErrnoWarning(errno, "QFontEngineQPF: access() failed for %s", qPrintable(qws_fontCacheDir()));
       
   382 #endif
       
   383                 return;
       
   384             }
       
   385         }
       
   386     }
       
   387 
       
   388     QT_STATBUF st;
       
   389     if (QT_FSTAT(fd, &st)) {
       
   390 #if defined(DEBUG_FONTENGINE)
       
   391         qErrnoWarning(errno, "QFontEngineQPF: fstat failed!");
       
   392 #endif
       
   393         return;
       
   394     }
       
   395     dataSize = st.st_size;
       
   396 
       
   397 
       
   398     fontData = (const uchar *)::mmap(0, st.st_size, PROT_READ | (renderingFontEngine ? PROT_WRITE : 0), MAP_SHARED, fd, 0);
       
   399     if (!fontData || fontData == (const uchar *)MAP_FAILED) {
       
   400 #if defined(DEBUG_FONTENGINE)
       
   401         perror("mmap failed");
       
   402 #endif
       
   403         fontData = 0;
       
   404         return;
       
   405     }
       
   406 #endif //QT_FONTS_ARE_RESOURCES
       
   407 
       
   408     if (!verifyHeader(fontData, dataSize)) {
       
   409 #if defined(DEBUG_FONTENGINE)
       
   410         qDebug() << "verifyHeader failed!";
       
   411 #endif
       
   412         return;
       
   413     }
       
   414 
       
   415     const Header *header = reinterpret_cast<const Header *>(fontData);
       
   416 
       
   417     readOnly = (header->lock == 0xffffffff);
       
   418 
       
   419     const uchar *data = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize);
       
   420     const uchar *endPtr = fontData + dataSize;
       
   421     while (data <= endPtr - 8) {
       
   422         quint16 blockTag = readValue<quint16>(data);
       
   423         data += 2; // skip padding
       
   424         quint32 blockSize = readValue<quint32>(data);
       
   425 
       
   426         if (blockTag == CMapBlock) {
       
   427             cmapOffset = data - fontData;
       
   428             cmapSize = blockSize;
       
   429         } else if (blockTag == GMapBlock) {
       
   430             glyphMapOffset = data - fontData;
       
   431             glyphMapEntries = blockSize / 4;
       
   432         } else if (blockTag == GlyphBlock) {
       
   433             glyphDataOffset = data - fontData;
       
   434             glyphDataSize = blockSize;
       
   435         }
       
   436 
       
   437         data += blockSize;
       
   438     }
       
   439 
       
   440     face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
       
   441     face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
       
   442 #if !defined(QT_NO_FREETYPE) && !defined(QT_FONTS_ARE_RESOURCES)
       
   443     freetype = QFreetypeFace::getFace(face_id);
       
   444     if (!freetype) {
       
   445         QString newPath =
       
   446 #ifndef QT_NO_SETTINGS
       
   447             QLibraryInfo::location(QLibraryInfo::LibrariesPath) +
       
   448 #endif
       
   449                           QLatin1String("/fonts/") +
       
   450                           QFileInfo(QFile::decodeName(face_id.filename)).fileName();
       
   451         face_id.filename = QFile::encodeName(newPath);
       
   452         freetype = QFreetypeFace::getFace(face_id);
       
   453     }
       
   454     if (freetype) {
       
   455         const quint32 qpfTtfRevision = extractHeaderField(fontData, Tag_FontRevision).toUInt();
       
   456         uchar data[4];
       
   457         uint length = 4;
       
   458         bool ok = freetype->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd'), data, &length);
       
   459         if (!ok || length != 4
       
   460             || qFromBigEndian<quint32>(data) != qpfTtfRevision) {
       
   461             freetype->release(face_id);
       
   462             freetype = 0;
       
   463         }
       
   464     }
       
   465     if (!cmapOffset && freetype) {
       
   466         freetypeCMapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
       
   467         externalCMap = reinterpret_cast<const uchar *>(freetypeCMapTable.constData());
       
   468         cmapSize = freetypeCMapTable.size();
       
   469     }
       
   470 #endif
       
   471 
       
   472     // get the real cmap
       
   473     if (cmapOffset) {
       
   474         int tableSize = cmapSize;
       
   475         const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
       
   476         if (cmapPtr)
       
   477             cmapOffset = cmapPtr - fontData;
       
   478         else
       
   479             cmapOffset = 0;
       
   480     } else if (externalCMap) {
       
   481         int tableSize = cmapSize;
       
   482         externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
       
   483     }
       
   484 
       
   485     // verify all the positions in the glyphMap
       
   486     if (glyphMapOffset) {
       
   487         const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
       
   488         for (uint i = 0; i < glyphMapEntries; ++i) {
       
   489             quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]);
       
   490             if (glyphDataPos == 0xffffffff)
       
   491                 continue;
       
   492             if (glyphDataPos >= glyphDataSize) {
       
   493                 // error
       
   494                 glyphMapOffset = 0;
       
   495                 glyphMapEntries = 0;
       
   496                 break;
       
   497             }
       
   498         }
       
   499     }
       
   500 
       
   501 #if defined(DEBUG_FONTENGINE)
       
   502     if (!isValid())
       
   503         qDebug() << "fontData" <<  fontData << "dataSize" << dataSize
       
   504                  << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
       
   505                  << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
       
   506                  << "fd" << fd << "glyphDataSize" << glyphDataSize;
       
   507 #endif
       
   508 #if defined(Q_WS_QWS)
       
   509     if (isValid() && renderingFontEngine)
       
   510         qt_fbdpy->sendFontCommand(QWSFontCommand::StartedUsingFont, encodedFileName);
       
   511 #endif
       
   512 }
       
   513 
       
   514 QFontEngineQPF::~QFontEngineQPF()
       
   515 {
       
   516 #if defined(Q_WS_QWS)
       
   517     if (isValid() && renderingFontEngine) {
       
   518         QT_TRY {
       
   519             qt_fbdpy->sendFontCommand(QWSFontCommand::StoppedUsingFont, encodedFileName);
       
   520         } QT_CATCH(...) {
       
   521             qDebug("QFontEngineQPF::~QFontEngineQPF: Out of memory");
       
   522             // ignore.
       
   523         }
       
   524     }
       
   525 #endif
       
   526     delete renderingFontEngine;
       
   527     if (fontData) {
       
   528         if (munmap((void *)fontData, dataSize) == -1) {
       
   529 #if defined(DEBUG_FONTENGINE)
       
   530             qErrnoWarning(errno, "~QFontEngineQPF: Unable to munmap");
       
   531 #endif
       
   532         }
       
   533     }
       
   534     if (fd != -1)
       
   535         ::close(fd);
       
   536 #if !defined(QT_NO_FREETYPE)
       
   537     if (freetype)
       
   538         freetype->release(face_id);
       
   539 #endif
       
   540 }
       
   541 
       
   542 bool QFontEngineQPF::getSfntTableData(uint tag, uchar *buffer, uint *length) const
       
   543 {
       
   544 #if !defined(QT_NO_FREETYPE)
       
   545     if (freetype)
       
   546         return freetype->getSfntTable(tag, buffer, length);
       
   547 #endif
       
   548     Q_UNUSED(tag);
       
   549     Q_UNUSED(buffer);
       
   550     *length = 0;
       
   551     return false;
       
   552 }
       
   553 
       
   554 bool QFontEngineQPF::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
       
   555 {
       
   556     if (!externalCMap && !cmapOffset && renderingFontEngine) {
       
   557         if (!renderingFontEngine->stringToCMap(str, len, glyphs, nglyphs, flags))
       
   558             return false;
       
   559 #ifndef QT_NO_FREETYPE
       
   560         const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(*glyphs);
       
   561 #endif
       
   562         return true;
       
   563     }
       
   564 
       
   565     if (*nglyphs < len) {
       
   566         *nglyphs = len;
       
   567         return false;
       
   568     }
       
   569 
       
   570 #if defined(DEBUG_FONTENGINE)
       
   571     QSet<QChar> seenGlyphs;
       
   572 #endif
       
   573 
       
   574     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
       
   575 
       
   576     bool mirrored = flags & QTextEngine::RightToLeft;
       
   577     int glyph_pos = 0;
       
   578     if (symbol) {
       
   579         for (int i = 0; i < len; ++i) {
       
   580             unsigned int uc = getChar(str, i, len);
       
   581             if (mirrored)
       
   582                 uc = QChar::mirroredChar(uc);
       
   583             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
       
   584             if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
       
   585                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
       
   586             ++glyph_pos;
       
   587         }
       
   588     } else {
       
   589         for (int i = 0; i < len; ++i) {
       
   590             unsigned int uc = getChar(str, i, len);
       
   591             if (mirrored)
       
   592                 uc = QChar::mirroredChar(uc);
       
   593             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
       
   594 #if 0 && defined(DEBUG_FONTENGINE)
       
   595             QChar c(uc);
       
   596             if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
       
   597                 qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
       
   598 
       
   599             seenGlyphs.insert(c);
       
   600 #endif
       
   601             ++glyph_pos;
       
   602         }
       
   603     }
       
   604 
       
   605     *nglyphs = glyph_pos;
       
   606     glyphs->numGlyphs = glyph_pos;
       
   607     recalcAdvances(glyphs, flags);
       
   608     return true;
       
   609 }
       
   610 
       
   611 void QFontEngineQPF::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
       
   612 {
       
   613 #ifndef QT_NO_FREETYPE
       
   614     const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(*glyphs);
       
   615 #endif
       
   616     for (int i = 0; i < glyphs->numGlyphs; ++i) {
       
   617         const Glyph *g = findGlyph(glyphs->glyphs[i]);
       
   618         if (!g) {
       
   619             glyphs->glyphs[i] = 0;
       
   620             continue;
       
   621         }
       
   622         glyphs->advances_x[i] = g->advance;
       
   623         glyphs->advances_y[i] = 0;
       
   624     }
       
   625 }
       
   626 
       
   627 QImage QFontEngineQPF::alphaMapForGlyph(glyph_t g)
       
   628 {
       
   629     const Glyph *glyph = findGlyph(g);
       
   630     if (!glyph)
       
   631 	return QImage();
       
   632 
       
   633     const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
       
   634 
       
   635     QImage image(glyph->width, glyph->height, QImage::Format_Indexed8);
       
   636     for (int j=0; j<256; ++j)
       
   637 	image.setColor(j, qRgba(0, 0, 0, j));
       
   638 
       
   639     for (int i=0; i<glyph->height; ++i) {
       
   640 	memcpy(image.scanLine(i), bits, glyph->bytesPerLine);
       
   641 	bits += glyph->bytesPerLine;
       
   642     }
       
   643     return image;
       
   644 }
       
   645 
       
   646 void QFontEngineQPF::draw(QPaintEngine *p, qreal _x, qreal _y, const QTextItemInt &si)
       
   647 {
       
   648     QPaintEngineState *pState = p->state;
       
   649     QRasterPaintEngine *paintEngine = static_cast<QRasterPaintEngine*>(p);
       
   650 
       
   651     QTransform matrix = pState->transform();
       
   652     matrix.translate(_x, _y);
       
   653     QFixed x = QFixed::fromReal(matrix.dx());
       
   654     QFixed y = QFixed::fromReal(matrix.dy());
       
   655 
       
   656     QVarLengthArray<QFixedPoint> positions;
       
   657     QVarLengthArray<glyph_t> glyphs;
       
   658     getGlyphPositions(si.glyphs, matrix, si.flags, glyphs, positions);
       
   659     if (glyphs.size() == 0)
       
   660         return;
       
   661 
       
   662     for(int i = 0; i < glyphs.size(); i++) {
       
   663         const Glyph *glyph = findGlyph(glyphs[i]);
       
   664         if (!glyph)
       
   665             continue;
       
   666 
       
   667         const int depth = 8; //###
       
   668 
       
   669         paintEngine->alphaPenBlt(reinterpret_cast<const uchar *>(glyph) + sizeof(Glyph), glyph->bytesPerLine, depth,
       
   670                                      qRound(positions[i].x) + glyph->x,
       
   671                                      qRound(positions[i].y) + glyph->y,
       
   672                                      glyph->width, glyph->height);
       
   673     }
       
   674 }
       
   675 
       
   676 void QFontEngineQPF::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
       
   677 {
       
   678     if (renderingFontEngine &&
       
   679         (renderingFontEngine->type() != QFontEngine::Proxy
       
   680          || static_cast<QProxyFontEngine *>(renderingFontEngine)->capabilities() & QAbstractFontEngine::CanOutlineGlyphs)) {
       
   681         renderingFontEngine->addOutlineToPath(x, y, glyphs, path, flags);
       
   682         return;
       
   683     }
       
   684     addBitmapFontToPath(x, y, glyphs, path, flags);
       
   685 }
       
   686 
       
   687 glyph_metrics_t QFontEngineQPF::boundingBox(const QGlyphLayout &glyphs)
       
   688 {
       
   689 #ifndef QT_NO_FREETYPE
       
   690     const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(glyphs);
       
   691 #endif
       
   692 
       
   693     glyph_metrics_t overall;
       
   694     // initialize with line height, we get the same behaviour on all platforms
       
   695     overall.y = -ascent();
       
   696     overall.height = ascent() + descent() + 1;
       
   697 
       
   698     QFixed ymax = 0;
       
   699     QFixed xmax = 0;
       
   700     for (int i = 0; i < glyphs.numGlyphs; i++) {
       
   701         const Glyph *g = findGlyph(glyphs.glyphs[i]);
       
   702         if (!g)
       
   703             continue;
       
   704 
       
   705         QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
       
   706         QFixed y = overall.yoff + glyphs.offsets[i].y + g->y;
       
   707         overall.x = qMin(overall.x, x);
       
   708         overall.y = qMin(overall.y, y);
       
   709         xmax = qMax(xmax, x + g->width);
       
   710         ymax = qMax(ymax, y + g->height);
       
   711         overall.xoff += g->advance;
       
   712     }
       
   713     overall.height = qMax(overall.height, ymax - overall.y);
       
   714     overall.width = xmax - overall.x;
       
   715 
       
   716     return overall;
       
   717 }
       
   718 
       
   719 glyph_metrics_t QFontEngineQPF::boundingBox(glyph_t glyph)
       
   720 {
       
   721 #ifndef QT_NO_FREETYPE
       
   722     {
       
   723         QGlyphLayoutArray<1> tmp;
       
   724         tmp.glyphs[0] = glyph;
       
   725         const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(tmp);
       
   726     }
       
   727 #endif
       
   728     glyph_metrics_t overall;
       
   729     const Glyph *g = findGlyph(glyph);
       
   730     if (!g)
       
   731         return overall;
       
   732     overall.x = g->x;
       
   733     overall.y = g->y;
       
   734     overall.width = g->width;
       
   735     overall.height = g->height;
       
   736     overall.xoff = g->advance;
       
   737     return overall;
       
   738 }
       
   739 
       
   740 QFixed QFontEngineQPF::ascent() const
       
   741 {
       
   742     return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
       
   743 }
       
   744 
       
   745 QFixed QFontEngineQPF::descent() const
       
   746 {
       
   747     return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
       
   748 }
       
   749 
       
   750 QFixed QFontEngineQPF::leading() const
       
   751 {
       
   752     return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
       
   753 }
       
   754 
       
   755 qreal QFontEngineQPF::maxCharWidth() const
       
   756 {
       
   757     return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
       
   758 }
       
   759 
       
   760 qreal QFontEngineQPF::minLeftBearing() const
       
   761 {
       
   762     return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
       
   763 }
       
   764 
       
   765 qreal QFontEngineQPF::minRightBearing() const
       
   766 {
       
   767     return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
       
   768 }
       
   769 
       
   770 QFixed QFontEngineQPF::underlinePosition() const
       
   771 {
       
   772     return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
       
   773 }
       
   774 
       
   775 QFixed QFontEngineQPF::lineThickness() const
       
   776 {
       
   777     return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
       
   778 }
       
   779 
       
   780 QFontEngine::Type QFontEngineQPF::type() const
       
   781 {
       
   782     return QFontEngine::QPF2;
       
   783 }
       
   784 
       
   785 bool QFontEngineQPF::canRender(const QChar *string, int len)
       
   786 {
       
   787     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
       
   788 
       
   789     if (symbol) {
       
   790         for (int i = 0; i < len; ++i) {
       
   791             unsigned int uc = getChar(string, i, len);
       
   792             glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
       
   793             if(!g && uc < 0x100)
       
   794                 g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
       
   795             if (!g)
       
   796                 return false;
       
   797         }
       
   798     } else {
       
   799         for (int i = 0; i < len; ++i) {
       
   800             unsigned int uc = getChar(string, i, len);
       
   801             if (!getTrueTypeGlyphIndex(cmap, uc))
       
   802                 return false;
       
   803         }
       
   804     }
       
   805     return true;
       
   806 }
       
   807 
       
   808 bool QFontEngineQPF::isValid() const
       
   809 {
       
   810     return fontData && dataSize && (cmapOffset || externalCMap || renderingFontEngine)
       
   811            && glyphMapOffset && glyphDataOffset && (fd >= 0 || glyphDataSize > 0);
       
   812 }
       
   813 
       
   814 #if !defined(QT_NO_FREETYPE)
       
   815 FT_Face QFontEngineQPF::lockFace() const
       
   816 {
       
   817     Q_ASSERT(freetype);
       
   818     freetype->lock();
       
   819     FT_Face face = freetype->face;
       
   820 
       
   821     // ### not perfect
       
   822     const int ysize = fontDef.pixelSize << 6;
       
   823     const int xsize = ysize;
       
   824 
       
   825     if (freetype->xsize != xsize || freetype->ysize != ysize) {
       
   826         FT_Set_Char_Size(face, xsize, ysize, 0, 0);
       
   827         freetype->xsize = xsize;
       
   828         freetype->ysize = ysize;
       
   829     }
       
   830     FT_Matrix identityMatrix;
       
   831     identityMatrix.xx = 0x10000;
       
   832     identityMatrix.yy = 0x10000;
       
   833     identityMatrix.xy = 0;
       
   834     identityMatrix.yx = 0;
       
   835     if (freetype->matrix.xx != identityMatrix.xx ||
       
   836         freetype->matrix.yy != identityMatrix.yy ||
       
   837         freetype->matrix.xy != identityMatrix.xy ||
       
   838         freetype->matrix.yx != identityMatrix.yx) {
       
   839         freetype->matrix = identityMatrix;
       
   840         FT_Set_Transform(face, &freetype->matrix, 0);
       
   841     }
       
   842     return face;
       
   843 }
       
   844 
       
   845 void QFontEngineQPF::unlockFace() const
       
   846 {
       
   847     freetype->unlock();
       
   848 }
       
   849 
       
   850 void QFontEngineQPF::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
       
   851 {
       
   852     if (!kerning_pairs_loaded) {
       
   853         kerning_pairs_loaded = true;
       
   854         if (freetype) {
       
   855             lockFace();
       
   856             if (freetype->face->size->metrics.x_ppem != 0) {
       
   857                 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
       
   858                 unlockFace();
       
   859                 const_cast<QFontEngineQPF *>(this)->loadKerningPairs(scalingFactor);
       
   860             } else {
       
   861                 unlockFace();
       
   862             }
       
   863         }
       
   864     }
       
   865     QFontEngine::doKerning(g, flags);
       
   866 }
       
   867 
       
   868 HB_Error QFontEngineQPF::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
       
   869 {
       
   870     if (!freetype)
       
   871         return HB_Err_Not_Covered;
       
   872     lockFace();
       
   873     HB_Error result = freetype->getPointInOutline(glyph, flags, point, xpos, ypos, nPoints);
       
   874     unlockFace();
       
   875     return result;
       
   876 }
       
   877 
       
   878 QFixed QFontEngineQPF::emSquareSize() const
       
   879 {
       
   880     if (!freetype)
       
   881         return QFontEngine::emSquareSize();
       
   882     if (FT_IS_SCALABLE(freetype->face))
       
   883         return freetype->face->units_per_EM;
       
   884     else
       
   885         return freetype->face->size->metrics.y_ppem;
       
   886 }
       
   887 
       
   888 void QFontEngineQPF::ensureGlyphsLoaded(const QGlyphLayout &glyphs)
       
   889 {
       
   890     if (readOnly)
       
   891         return;
       
   892     bool locked = false;
       
   893     for (int i = 0; i < glyphs.numGlyphs; ++i) {
       
   894         if (!glyphs.glyphs[i])
       
   895             continue;
       
   896         const Glyph *g = findGlyph(glyphs.glyphs[i]);
       
   897         if (g)
       
   898             continue;
       
   899         if (!locked) {
       
   900             if (!lockFile())
       
   901                 return;
       
   902             locked = true;
       
   903             g = findGlyph(glyphs.glyphs[i]);
       
   904             if (g)
       
   905                 continue;
       
   906         }
       
   907         loadGlyph(glyphs.glyphs[i]);
       
   908     }
       
   909     if (locked) {
       
   910         unlockFile();
       
   911 #if defined(DEBUG_FONTENGINE)
       
   912         qDebug() << "Finished rendering glyphs\n";
       
   913 #endif
       
   914     }
       
   915 }
       
   916 
       
   917 void QFontEngineQPF::loadGlyph(glyph_t glyph)
       
   918 {
       
   919     quint32 glyphPos = ~0;
       
   920 
       
   921     if (!renderingFontEngine)
       
   922         return;
       
   923 
       
   924     QImage img = renderingFontEngine->alphaMapForGlyph(glyph).convertToFormat(QImage::Format_Indexed8);
       
   925     glyph_metrics_t metrics = renderingFontEngine->boundingBox(glyph);
       
   926     renderingFontEngine->removeGlyphFromCache(glyph);
       
   927 
       
   928     off_t oldSize = ::lseek(fd, 0, SEEK_END);
       
   929     if (oldSize == (off_t)-1)
       
   930         return;
       
   931 
       
   932     Glyph g;
       
   933     g.width = img.width();
       
   934     g.height = img.height();
       
   935     g.bytesPerLine = img.bytesPerLine();
       
   936     g.x = qRound(metrics.x);
       
   937     g.y = qRound(metrics.y);
       
   938     g.advance = qRound(metrics.xoff);
       
   939 
       
   940     QT_WRITE(fd, &g, sizeof(g));
       
   941     QT_WRITE(fd, img.bits(), img.numBytes());
       
   942 
       
   943     glyphPos = oldSize - glyphDataOffset;
       
   944 #if 0 && defined(DEBUG_FONTENGINE)
       
   945     qDebug() << "glyphPos for new glyph" << glyph << "is" << glyphPos << "oldSize" << oldSize << "glyphDataOffset" << glyphDataOffset;
       
   946 #endif
       
   947 
       
   948     quint32 *gmap = (quint32 *)(fontData + glyphMapOffset);
       
   949     gmap[glyph] = qToBigEndian(glyphPos);
       
   950 
       
   951     glyphDataSize = glyphPos + sizeof(g) + img.numBytes();
       
   952     quint32 *blockSizePtr = (quint32 *)(fontData + glyphDataOffset - 4);
       
   953     *blockSizePtr = qToBigEndian(glyphDataSize);
       
   954 }
       
   955 
       
   956 bool QFontEngineQPF::lockFile()
       
   957 {
       
   958     // #### this does not handle the case when the process holding the
       
   959     // lock hangs for some reason
       
   960     struct flock lock;
       
   961     lock.l_type = F_WRLCK;
       
   962     lock.l_whence = SEEK_SET;
       
   963     lock.l_start = 0;
       
   964     lock.l_len = 0; // lock the whole file
       
   965     while (fcntl(fd, F_SETLKW, &lock) != 0) {
       
   966         if (errno == EINTR)
       
   967             continue;
       
   968         perror("locking qpf");
       
   969         return false;
       
   970     }
       
   971     Header *header = (Header *)fontData;
       
   972     if (header->lock) {
       
   973         lock.l_type = F_UNLCK;
       
   974         if (fcntl(fd, F_SETLK, &lock) != 0)
       
   975             perror("unlocking possibly corrupt qpf");
       
   976         return false;
       
   977     }
       
   978 #if defined(Q_WS_QWS)
       
   979     extern int qws_client_id;
       
   980     // qws_client_id == 0 means we're the server. in this case we just
       
   981     // set the id to 1
       
   982     header->lock = qws_client_id ? qws_client_id : 1;
       
   983 #else
       
   984     header->lock = 1;
       
   985 #endif
       
   986     return true;
       
   987 }
       
   988 
       
   989 void QFontEngineQPF::unlockFile()
       
   990 {
       
   991     ((Header *)fontData)->lock = 0;
       
   992 
       
   993     struct flock lock;
       
   994     lock.l_type = F_UNLCK;
       
   995     lock.l_whence = SEEK_SET;
       
   996     lock.l_start = 0;
       
   997     lock.l_len = 0; // lock the whole file
       
   998     if (fcntl(fd, F_SETLK, &lock) != 0) {
       
   999         perror("unlocking qpf");
       
  1000     }
       
  1001 
       
  1002     remapFontData();
       
  1003 }
       
  1004 
       
  1005 void QFontEngineQPF::remapFontData()
       
  1006 {
       
  1007     off_t newFileSize = ::lseek(fd, 0, SEEK_END);
       
  1008     if (newFileSize == (off_t)-1) {
       
  1009 #ifdef DEBUG_FONTENGINE
       
  1010         perror("QFontEngineQPF::remapFontData: lseek failed");
       
  1011 #endif
       
  1012         fontData = 0;
       
  1013         return;
       
  1014     }
       
  1015 
       
  1016 #ifndef QT_NO_MREMAP
       
  1017     fontData = static_cast<uchar *>(::mremap(const_cast<uchar *>(fontData), dataSize, newFileSize, MREMAP_MAYMOVE));
       
  1018     if (!fontData || fontData == (const uchar *)MAP_FAILED) {
       
  1019 #  if defined(DEBUG_FONTENGINE)
       
  1020         perror("QFontEngineQPF::remapFontData(): mremap failed");
       
  1021 #  endif
       
  1022         fontData = 0;
       
  1023     }
       
  1024 
       
  1025     if (!fontData)
       
  1026 #endif // QT_NO_MREMAP
       
  1027     {
       
  1028         int status = ::munmap((void *)fontData, dataSize);
       
  1029         if (status != 0)
       
  1030             qErrnoWarning(status, "QFontEngineQPF::remapFomrData: munmap failed!");
       
  1031 
       
  1032         fontData = (const uchar *)::mmap(0, newFileSize, PROT_READ | (renderingFontEngine ? PROT_WRITE : 0),
       
  1033                                          MAP_SHARED, fd, 0);
       
  1034         if (!fontData || fontData == (const uchar *)MAP_FAILED) {
       
  1035 #  if defined(DEBUG_FONTENGINE)
       
  1036             perror("mmap failed");
       
  1037 #  endif
       
  1038             fontData = 0;
       
  1039             return;
       
  1040         }
       
  1041     }
       
  1042 
       
  1043     dataSize = newFileSize;
       
  1044     glyphDataSize = newFileSize - glyphDataOffset;
       
  1045 #if defined(DEBUG_FONTENGINE)
       
  1046     qDebug() << "remapped the font file to" << newFileSize << "bytes";
       
  1047 #endif
       
  1048 }
       
  1049 
       
  1050 #endif // QT_NO_FREETYPE
       
  1051 
       
  1052 void QPFGenerator::generate()
       
  1053 {
       
  1054     writeHeader();
       
  1055     writeGMap();
       
  1056     writeBlock(QFontEngineQPF::GlyphBlock, QByteArray());
       
  1057 
       
  1058     dev->seek(4); // position of header.lock
       
  1059     writeUInt32(0);
       
  1060 }
       
  1061 
       
  1062 void QPFGenerator::writeHeader()
       
  1063 {
       
  1064     QFontEngineQPF::Header header;
       
  1065 
       
  1066     header.magic[0] = 'Q';
       
  1067     header.magic[1] = 'P';
       
  1068     header.magic[2] = 'F';
       
  1069     header.magic[3] = '2';
       
  1070     header.lock = 1;
       
  1071     header.majorVersion = QFontEngineQPF::CurrentMajorVersion;
       
  1072     header.minorVersion = QFontEngineQPF::CurrentMinorVersion;
       
  1073     header.dataSize = 0;
       
  1074     dev->write((const char *)&header, sizeof(header));
       
  1075 
       
  1076     writeTaggedString(QFontEngineQPF::Tag_FontName, fe->fontDef.family.toUtf8());
       
  1077 
       
  1078     QFontEngine::FaceId face = fe->faceId();
       
  1079     writeTaggedString(QFontEngineQPF::Tag_FileName, face.filename);
       
  1080     writeTaggedUInt32(QFontEngineQPF::Tag_FileIndex, face.index);
       
  1081 
       
  1082     {
       
  1083         uchar data[4];
       
  1084         uint len = 4;
       
  1085         bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
       
  1086         if (ok) {
       
  1087             const quint32 revision = qFromBigEndian<quint32>(data);
       
  1088             writeTaggedUInt32(QFontEngineQPF::Tag_FontRevision, revision);
       
  1089         }
       
  1090     }
       
  1091 
       
  1092     writeTaggedQFixed(QFontEngineQPF::Tag_Ascent, fe->ascent());
       
  1093     writeTaggedQFixed(QFontEngineQPF::Tag_Descent, fe->descent());
       
  1094     writeTaggedQFixed(QFontEngineQPF::Tag_Leading, fe->leading());
       
  1095     writeTaggedQFixed(QFontEngineQPF::Tag_XHeight, fe->xHeight());
       
  1096     writeTaggedQFixed(QFontEngineQPF::Tag_AverageCharWidth, fe->averageCharWidth());
       
  1097     writeTaggedQFixed(QFontEngineQPF::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth()));
       
  1098     writeTaggedQFixed(QFontEngineQPF::Tag_LineThickness, fe->lineThickness());
       
  1099     writeTaggedQFixed(QFontEngineQPF::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing()));
       
  1100     writeTaggedQFixed(QFontEngineQPF::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing()));
       
  1101     writeTaggedQFixed(QFontEngineQPF::Tag_UnderlinePosition, fe->underlinePosition());
       
  1102     writeTaggedUInt8(QFontEngineQPF::Tag_PixelSize, fe->fontDef.pixelSize);
       
  1103     writeTaggedUInt8(QFontEngineQPF::Tag_Weight, fe->fontDef.weight);
       
  1104     writeTaggedUInt8(QFontEngineQPF::Tag_Style, fe->fontDef.style);
       
  1105 
       
  1106     writeTaggedUInt8(QFontEngineQPF::Tag_GlyphFormat, QFontEngineQPF::AlphamapGlyphs);
       
  1107 
       
  1108     writeTaggedString(QFontEngineQPF::Tag_EndOfHeader, QByteArray());
       
  1109     align4();
       
  1110 
       
  1111     const quint64 size = dev->pos();
       
  1112     header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
       
  1113     dev->seek(0);
       
  1114     dev->write((const char *)&header, sizeof(header));
       
  1115     dev->seek(size);
       
  1116 }
       
  1117 
       
  1118 void QPFGenerator::writeGMap()
       
  1119 {
       
  1120     const quint16 glyphCount = fe->glyphCount();
       
  1121 
       
  1122     writeUInt16(QFontEngineQPF::GMapBlock);
       
  1123     writeUInt16(0); // padding
       
  1124     writeUInt32(glyphCount * 4);
       
  1125 
       
  1126     QByteArray &buffer = dev->buffer();
       
  1127     const int numBytes = glyphCount * sizeof(quint32);
       
  1128     qint64 pos = buffer.size();
       
  1129     buffer.resize(pos + numBytes);
       
  1130     qMemSet(buffer.data() + pos, 0xff, numBytes);
       
  1131     dev->seek(pos + numBytes);
       
  1132 }
       
  1133 
       
  1134 void QPFGenerator::writeBlock(QFontEngineQPF::BlockTag tag, const QByteArray &data)
       
  1135 {
       
  1136     writeUInt16(tag);
       
  1137     writeUInt16(0); // padding
       
  1138     const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
       
  1139     writeUInt32(data.size() + padSize);
       
  1140     dev->write(data);
       
  1141     for (int i = 0; i < padSize; ++i)
       
  1142         writeUInt8(0);
       
  1143 }
       
  1144 
       
  1145 void QPFGenerator::writeTaggedString(QFontEngineQPF::HeaderTag tag, const QByteArray &string)
       
  1146 {
       
  1147     writeUInt16(tag);
       
  1148     writeUInt16(string.length());
       
  1149     dev->write(string);
       
  1150 }
       
  1151 
       
  1152 void QPFGenerator::writeTaggedUInt32(QFontEngineQPF::HeaderTag tag, quint32 value)
       
  1153 {
       
  1154     writeUInt16(tag);
       
  1155     writeUInt16(sizeof(value));
       
  1156     writeUInt32(value);
       
  1157 }
       
  1158 
       
  1159 void QPFGenerator::writeTaggedUInt8(QFontEngineQPF::HeaderTag tag, quint8 value)
       
  1160 {
       
  1161     writeUInt16(tag);
       
  1162     writeUInt16(sizeof(value));
       
  1163     writeUInt8(value);
       
  1164 }
       
  1165 
       
  1166 void QPFGenerator::writeTaggedQFixed(QFontEngineQPF::HeaderTag tag, QFixed value)
       
  1167 {
       
  1168     writeUInt16(tag);
       
  1169     writeUInt16(sizeof(quint32));
       
  1170     writeUInt32(value.value());
       
  1171 }
       
  1172 
       
  1173 #endif // QT_NO_QWS_QPF2
       
  1174 
       
  1175 /*
       
  1176     Creates a new multi qws engine.
       
  1177 
       
  1178     This function takes ownership of the QFontEngine, increasing it's refcount.
       
  1179 */
       
  1180 QFontEngineMultiQWS::QFontEngineMultiQWS(QFontEngine *fe, int _script, const QStringList &fallbacks)
       
  1181     : QFontEngineMulti(fallbacks.size() + 1),
       
  1182       fallbackFamilies(fallbacks), script(_script)
       
  1183 {
       
  1184     engines[0] = fe;
       
  1185     fe->ref.ref();
       
  1186     fontDef = engines[0]->fontDef;
       
  1187 }
       
  1188 
       
  1189 void QFontEngineMultiQWS::loadEngine(int at)
       
  1190 {
       
  1191     Q_ASSERT(at < engines.size());
       
  1192     Q_ASSERT(engines.at(at) == 0);
       
  1193 
       
  1194     QFontDef request = fontDef;
       
  1195     request.styleStrategy |= QFont::NoFontMerging;
       
  1196     request.family = fallbackFamilies.at(at-1);
       
  1197     engines[at] = QFontDatabase::findFont(script,
       
  1198                                           /*fontprivate*/0,
       
  1199                                           request);
       
  1200     Q_ASSERT(engines[at]);
       
  1201     engines[at]->ref.ref();
       
  1202     engines[at]->fontDef = request;
       
  1203 }
       
  1204 
       
  1205 void QFontEngineMultiQWS::draw(QPaintEngine */*p*/, qreal /*x*/, qreal /*y*/, const QTextItemInt &/*si*/)
       
  1206 {
       
  1207     qFatal("QFontEngineMultiQWS::draw should never be called!");
       
  1208 }
       
  1209 
       
  1210 QT_END_NAMESPACE