tools/makeqpf/qpf2.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 tools applications 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 "qpf2.h"
       
    43 
       
    44 #include <math.h>
       
    45 #include <private/qfontengine_p.h>
       
    46 #include <QFile>
       
    47 #include <qendian.h>
       
    48 
       
    49 QT_BEGIN_NAMESPACE
       
    50 
       
    51 #include "../../src/gui/text/qpfutil.cpp"
       
    52 
       
    53 int QPF::debugVerbosity = 0;
       
    54 
       
    55 // ### copied from qfontdatabase.cpp
       
    56 
       
    57 // see the Unicode subset bitfields in the MSDN docs
       
    58 static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
       
    59         // Any,
       
    60     { 127, 127 },
       
    61         // Latin,
       
    62     { 0, 127 },
       
    63         // Greek,
       
    64     { 7, 127 },
       
    65         // Cyrillic,
       
    66     { 9, 127 },
       
    67         // Armenian,
       
    68     { 10, 127 },
       
    69         // Hebrew,
       
    70     { 11, 127 },
       
    71         // Arabic,
       
    72     { 13, 127 },
       
    73         // Syriac,
       
    74     { 71, 127 },
       
    75     //Thaana,
       
    76     { 72, 127 },
       
    77     //Devanagari,
       
    78     { 15, 127 },
       
    79     //Bengali,
       
    80     { 16, 127 },
       
    81     //Gurmukhi,
       
    82     { 17, 127 },
       
    83     //Gujarati,
       
    84     { 18, 127 },
       
    85     //Oriya,
       
    86     { 19, 127 },
       
    87     //Tamil,
       
    88     { 20, 127 },
       
    89     //Telugu,
       
    90     { 21, 127 },
       
    91     //Kannada,
       
    92     { 22, 127 },
       
    93     //Malayalam,
       
    94     { 23, 127 },
       
    95     //Sinhala,
       
    96     { 73, 127 },
       
    97     //Thai,
       
    98     { 24, 127 },
       
    99     //Lao,
       
   100     { 25, 127 },
       
   101     //Tibetan,
       
   102     { 70, 127 },
       
   103     //Myanmar,
       
   104     { 74, 127 },
       
   105         // Georgian,
       
   106     { 26, 127 },
       
   107         // Khmer,
       
   108     { 80, 127 },
       
   109         // SimplifiedChinese,
       
   110     { 126, 127 },
       
   111         // TraditionalChinese,
       
   112     { 126, 127 },
       
   113         // Japanese,
       
   114     { 126, 127 },
       
   115         // Korean,
       
   116     { 56, 127 },
       
   117         // Vietnamese,
       
   118     { 0, 127 }, // same as latin1
       
   119         // Other,
       
   120     { 126, 127 }
       
   121 };
       
   122 
       
   123 #define SimplifiedChineseCsbBit 18
       
   124 #define TraditionalChineseCsbBit 20
       
   125 #define JapaneseCsbBit 17
       
   126 #define KoreanCsbBit 21
       
   127 
       
   128 static QList<QFontDatabase::WritingSystem> determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2])
       
   129 {
       
   130     QList<QFontDatabase::WritingSystem> writingSystems;
       
   131     bool hasScript = false;
       
   132 
       
   133     int i;
       
   134     for(i = 0; i < QFontDatabase::WritingSystemsCount; i++) {
       
   135         int bit = requiredUnicodeBits[i][0];
       
   136         int index = bit/32;
       
   137         int flag =  1 << (bit&31);
       
   138         if (bit != 126 && unicodeRange[index] & flag) {
       
   139             bit = requiredUnicodeBits[i][1];
       
   140             index = bit/32;
       
   141 
       
   142             flag =  1 << (bit&31);
       
   143             if (bit == 127 || unicodeRange[index] & flag) {
       
   144                 writingSystems.append(QFontDatabase::WritingSystem(i));
       
   145                 hasScript = true;
       
   146                 // qDebug("font %s: index=%d, flag=%8x supports script %d", familyName.latin1(), index, flag, i);
       
   147             }
       
   148         }
       
   149     }
       
   150     if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) {
       
   151         writingSystems.append(QFontDatabase::SimplifiedChinese);
       
   152         hasScript = true;
       
   153         //qDebug("font %s supports Simplified Chinese", familyName.latin1());
       
   154     }
       
   155     if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
       
   156         writingSystems.append(QFontDatabase::TraditionalChinese);
       
   157         hasScript = true;
       
   158         //qDebug("font %s supports Traditional Chinese", familyName.latin1());
       
   159     }
       
   160     if(codePageRange[0] & (1 << JapaneseCsbBit)) {
       
   161         writingSystems.append(QFontDatabase::Japanese);
       
   162         hasScript = true;
       
   163         //qDebug("font %s supports Japanese", familyName.latin1());
       
   164     }
       
   165     if(codePageRange[0] & (1 << KoreanCsbBit)) {
       
   166         writingSystems.append(QFontDatabase::Korean);
       
   167         hasScript = true;
       
   168         //qDebug("font %s supports Korean", familyName.latin1());
       
   169     }
       
   170     if (!hasScript)
       
   171         writingSystems.append(QFontDatabase::Symbol);
       
   172 
       
   173     return writingSystems;
       
   174 }
       
   175 
       
   176 static QByteArray getWritingSystems(QFontEngine *fontEngine)
       
   177 {
       
   178     QByteArray os2Table = fontEngine->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
       
   179     if (os2Table.isEmpty())
       
   180         return QByteArray();
       
   181 
       
   182     const uchar *data = reinterpret_cast<const uchar *>(os2Table.constData());
       
   183 
       
   184     quint32 unicodeRange[4] = {
       
   185         qFromBigEndian<quint32>(data + 42),
       
   186         qFromBigEndian<quint32>(data + 46),
       
   187         qFromBigEndian<quint32>(data + 50),
       
   188         qFromBigEndian<quint32>(data + 54)
       
   189     };
       
   190     quint32 codePageRange[2] = { qFromBigEndian<quint32>(data + 78), qFromBigEndian<quint32>(data + 82) };
       
   191     QList<QFontDatabase::WritingSystem> systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
       
   192 
       
   193     QByteArray bitField((QFontDatabase::WritingSystemsCount + 7) / 8, 0);
       
   194 
       
   195     for (int i = 0; i < systems.count(); ++i) {
       
   196         int bitPos = systems.at(i);
       
   197         bitField[bitPos / 8] = bitField.at(bitPos / 8) | (1 << (bitPos % 8));
       
   198     }
       
   199 
       
   200     return bitField;
       
   201 }
       
   202 
       
   203 static QString stringify(const QByteArray &bits)
       
   204 {
       
   205     QString result;
       
   206     for (int i = 0; i < bits.count(); ++i) {
       
   207         uchar currentByte = bits.at(i);
       
   208         for (int j = 0; j < 8; ++j) {
       
   209             if (currentByte & 1)
       
   210                 result += '1';
       
   211             else
       
   212                 result += '0';
       
   213             currentByte >>= 1;
       
   214         }
       
   215     }
       
   216     return result;
       
   217 }
       
   218 
       
   219 static void dumpWritingSystems(const QByteArray &bits)
       
   220 {
       
   221     QStringList writingSystems;
       
   222 
       
   223     QString bitString = stringify(bits);
       
   224     for (int i = 0; i < qMin(int(QFontDatabase::WritingSystemsCount), bitString.length()); ++i) {
       
   225         if (bitString.at(i) == QLatin1Char('1'))
       
   226             writingSystems << QFontDatabase::writingSystemName(QFontDatabase::WritingSystem(i));
       
   227     }
       
   228 
       
   229     qDebug() << "Supported writing systems:" << writingSystems;
       
   230 }
       
   231 
       
   232 static const char *headerTagNames[QFontEngineQPF::NumTags] = {
       
   233     "FontName",
       
   234     "FileName",
       
   235     "FileIndex",
       
   236     "FontRevision",
       
   237     "FreeText",
       
   238     "Ascent",
       
   239     "Descent",
       
   240     "Leading",
       
   241     "XHeight",
       
   242     "AverageCharWidth",
       
   243     "MaxCharWidth",
       
   244     "LineThickness",
       
   245     "MinLeftBearing",
       
   246     "MinRightBearing",
       
   247     "UnderlinePosition",
       
   248     "GlyphFormat",
       
   249     "PixelSize",
       
   250     "Weight",
       
   251     "Style",
       
   252     "EndOfHeader",
       
   253     "WritingSystems"
       
   254 };
       
   255 
       
   256 QString QPF::fileNameForFont(const QFont &f)
       
   257 {
       
   258     QString fileName = f.family().toLower() + "_" + QString::number(f.pixelSize())
       
   259                        + "_" + QString::number(f.weight())
       
   260                        + (f.italic() ? "_italic" : "")
       
   261                        + ".qpf2";
       
   262     fileName.replace(QLatin1Char(' '), QLatin1Char('_'));
       
   263     return fileName;
       
   264 }
       
   265 
       
   266 QByteArray QPF::generate(const QFont &font, int options, const QList<CharacterRange> &ranges, QString *originalFontFile)
       
   267 {
       
   268     QTextEngine engine("Test", font);
       
   269     engine.itemize();
       
   270     engine.shape(0);
       
   271     QFontEngine *fontEngine = engine.fontEngine(engine.layoutData->items[0]);
       
   272     if (fontEngine->type() == QFontEngine::Multi)
       
   273         fontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(0);
       
   274 
       
   275     if (originalFontFile)
       
   276         *originalFontFile = QFile::decodeName(fontEngine->faceId().filename);
       
   277 
       
   278     return generate(fontEngine, options, ranges);
       
   279 }
       
   280 
       
   281 QByteArray QPF::generate(QFontEngine *fontEngine, int options, const QList<CharacterRange> &ranges)
       
   282 {
       
   283     QPF font;
       
   284 
       
   285     font.options = options;
       
   286     font.addHeader(fontEngine);
       
   287     if (options & IncludeCMap)
       
   288         font.addCMap(fontEngine);
       
   289     font.addGlyphs(fontEngine, ranges);
       
   290 
       
   291     return font.qpf;
       
   292 }
       
   293 
       
   294 void QPF::addHeader(QFontEngine *fontEngine)
       
   295 {
       
   296     QFontEngineQPF::Header *header = reinterpret_cast<QFontEngineQPF::Header *>(addBytes(sizeof(QFontEngineQPF::Header)));
       
   297 
       
   298     header->magic[0] = 'Q';
       
   299     header->magic[1] = 'P';
       
   300     header->magic[2] = 'F';
       
   301     header->magic[3] = '2';
       
   302     if (options & RenderGlyphs)
       
   303         header->lock = 0xffffffff;
       
   304     else
       
   305         header->lock = 0;
       
   306     header->majorVersion = QFontEngineQPF::CurrentMajorVersion;
       
   307     header->minorVersion = QFontEngineQPF::CurrentMinorVersion;
       
   308     header->dataSize = 0;
       
   309     int oldSize = qpf.size();
       
   310 
       
   311     addTaggedString(QFontEngineQPF::Tag_FontName, fontEngine->fontDef.family.toUtf8());
       
   312 
       
   313     QFontEngine::FaceId face = fontEngine->faceId();
       
   314     addTaggedString(QFontEngineQPF::Tag_FileName, face.filename);
       
   315     addTaggedUInt32(QFontEngineQPF::Tag_FileIndex, face.index);
       
   316 
       
   317     {
       
   318         const QByteArray head = fontEngine->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd'));
       
   319         const quint32 revision = qFromBigEndian<quint32>(reinterpret_cast<const uchar *>(head.constData()) + 4);
       
   320         addTaggedUInt32(QFontEngineQPF::Tag_FontRevision, revision);
       
   321     }
       
   322 
       
   323     addTaggedQFixed(QFontEngineQPF::Tag_Ascent, fontEngine->ascent());
       
   324     addTaggedQFixed(QFontEngineQPF::Tag_Descent, fontEngine->descent());
       
   325     addTaggedQFixed(QFontEngineQPF::Tag_Leading, fontEngine->leading());
       
   326     addTaggedQFixed(QFontEngineQPF::Tag_XHeight, fontEngine->xHeight());
       
   327     addTaggedQFixed(QFontEngineQPF::Tag_AverageCharWidth, fontEngine->averageCharWidth());
       
   328     addTaggedQFixed(QFontEngineQPF::Tag_MaxCharWidth, QFixed::fromReal(fontEngine->maxCharWidth()));
       
   329     addTaggedQFixed(QFontEngineQPF::Tag_LineThickness, fontEngine->lineThickness());
       
   330     addTaggedQFixed(QFontEngineQPF::Tag_MinLeftBearing, QFixed::fromReal(fontEngine->minLeftBearing()));
       
   331     addTaggedQFixed(QFontEngineQPF::Tag_MinRightBearing, QFixed::fromReal(fontEngine->minRightBearing()));
       
   332     addTaggedQFixed(QFontEngineQPF::Tag_UnderlinePosition, fontEngine->underlinePosition());
       
   333     addTaggedUInt8(QFontEngineQPF::Tag_PixelSize, fontEngine->fontDef.pixelSize);
       
   334     addTaggedUInt8(QFontEngineQPF::Tag_Weight, fontEngine->fontDef.weight);
       
   335     addTaggedUInt8(QFontEngineQPF::Tag_Style, fontEngine->fontDef.style);
       
   336 
       
   337     QByteArray writingSystemBitField = getWritingSystems(fontEngine);
       
   338     if (!writingSystemBitField.isEmpty())
       
   339         addTaggedString(QFontEngineQPF::Tag_WritingSystems, writingSystemBitField);
       
   340 
       
   341     addTaggedUInt8(QFontEngineQPF::Tag_GlyphFormat, QFontEngineQPF::AlphamapGlyphs);
       
   342 
       
   343     addTaggedString(QFontEngineQPF::Tag_EndOfHeader, QByteArray());
       
   344     align4();
       
   345     header = reinterpret_cast<QFontEngineQPF::Header *>(qpf.data());
       
   346     header->dataSize = qToBigEndian<quint16>(qpf.size() - oldSize);
       
   347 }
       
   348 
       
   349 static uchar *appendBytes(QByteArray &array, int size)
       
   350 {
       
   351     int oldSize = array.size();
       
   352     array.resize(array.size() + size);
       
   353     return reinterpret_cast<uchar *>(array.data() + oldSize);
       
   354 }
       
   355 
       
   356 #define APPEND(type, value) \
       
   357     qToBigEndian<type>(value, appendBytes(cmap, sizeof(type)))
       
   358 
       
   359 struct CMapSegment
       
   360 {
       
   361     int start; // codepoints
       
   362     int end;
       
   363     int startGlyphIndex;
       
   364 };
       
   365 
       
   366 static QByteArray generateTrueTypeCMap(QFontEngine *fe)
       
   367 {
       
   368     QByteArray cmap;
       
   369     const int glyphCount = fe->glyphCount();
       
   370     if (!glyphCount)
       
   371         return cmap;
       
   372 
       
   373     // cmap header
       
   374     APPEND(quint16, 0); // table version number
       
   375     APPEND(quint16, 1); // number of tables
       
   376 
       
   377     // encoding record
       
   378     APPEND(quint16, 3); // platform-id
       
   379     APPEND(quint16, 10); // encoding-id (ucs-4)
       
   380     const int cmapOffset = cmap.size() + sizeof(quint32);
       
   381     APPEND(quint32, cmapOffset); // offset to sub-table
       
   382 
       
   383     APPEND(quint16, 4); // subtable format
       
   384     const int cmapTableLengthOffset = cmap.size();
       
   385     APPEND(quint16, 0); // length in bytes, will fill in later
       
   386     APPEND(quint16, 0); // language field
       
   387 
       
   388     QList<CMapSegment> segments;
       
   389     CMapSegment currentSegment;
       
   390     currentSegment.start = 0xffff;
       
   391     currentSegment.end = 0;
       
   392     currentSegment.startGlyphIndex = 0;
       
   393     quint32 previousGlyphIndex = 0xfffffffe;
       
   394     bool inSegment = false;
       
   395 
       
   396     QGlyphLayoutArray<10> layout;
       
   397     for (uint uc = 0; uc < 0x10000; ++uc) {
       
   398         QChar ch(uc);
       
   399         int nglyphs = 10;
       
   400 
       
   401         bool validGlyph = fe->stringToCMap(&ch, 1, &layout, &nglyphs, /*flags*/ 0)
       
   402                           && nglyphs == 1 && layout.glyphs[0];
       
   403 
       
   404         // leaving a segment?
       
   405         if (inSegment && (!validGlyph || layout.glyphs[0] != previousGlyphIndex + 1)) {
       
   406             Q_ASSERT(currentSegment.start != 0xffff);
       
   407             // store the current segment
       
   408             currentSegment.end = uc - 1;
       
   409             segments.append(currentSegment);
       
   410             currentSegment.start = 0xffff;
       
   411             inSegment = false;
       
   412         }
       
   413         // entering a new segment?
       
   414         if (validGlyph && (!inSegment || layout.glyphs[0] != previousGlyphIndex + 1)) {
       
   415             currentSegment.start = uc;
       
   416             currentSegment.startGlyphIndex = layout.glyphs[0];
       
   417             inSegment = true;
       
   418         }
       
   419 
       
   420         if (validGlyph)
       
   421             previousGlyphIndex = layout.glyphs[0];
       
   422         else
       
   423             previousGlyphIndex = 0xfffffffe;
       
   424     }
       
   425 
       
   426     currentSegment.start = 0xffff;
       
   427     currentSegment.end = 0xffff;
       
   428     currentSegment.startGlyphIndex = 0;
       
   429     segments.append(currentSegment);
       
   430 
       
   431     if (QPF::debugVerbosity > 3)
       
   432         qDebug() << "segments:" << segments.count();
       
   433 
       
   434     Q_ASSERT(!inSegment);
       
   435 
       
   436     const quint16 entrySelector = int(log2(segments.count()));
       
   437     const quint16 searchRange = 2 * (1 << entrySelector);
       
   438     const quint16 rangeShift = segments.count() * 2 - searchRange;
       
   439 
       
   440     if (QPF::debugVerbosity > 3)
       
   441         qDebug() << "entrySelector" << entrySelector << "searchRange" << searchRange
       
   442                  << "rangeShift" << rangeShift;
       
   443 
       
   444     APPEND(quint16, segments.count() * 2); // segCountX2
       
   445     APPEND(quint16, searchRange);
       
   446     APPEND(quint16, entrySelector);
       
   447     APPEND(quint16, rangeShift);
       
   448 
       
   449     // end character codes
       
   450     for (int i = 0; i < segments.count(); ++i)
       
   451         APPEND(quint16, segments.at(i).end);
       
   452 
       
   453     APPEND(quint16, 0); // pad
       
   454 
       
   455     // start character codes
       
   456     for (int i = 0; i < segments.count(); ++i)
       
   457         APPEND(quint16, segments.at(i).start);
       
   458 
       
   459     // id deltas
       
   460     for (int i = 0; i < segments.count(); ++i)
       
   461         APPEND(quint16, segments.at(i).startGlyphIndex - segments.at(i).start);
       
   462 
       
   463     // id range offsets
       
   464     for (int i = 0; i < segments.count(); ++i)
       
   465         APPEND(quint16, 0);
       
   466 
       
   467     uchar *lengthPtr = reinterpret_cast<uchar *>(cmap.data()) + cmapTableLengthOffset;
       
   468     qToBigEndian<quint16>(cmap.size() - cmapOffset, lengthPtr);
       
   469 
       
   470     return cmap;
       
   471 }
       
   472 
       
   473 void QPF::addCMap(QFontEngine *fontEngine)
       
   474 {
       
   475     QByteArray cmapTable = fontEngine->getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
       
   476     if (cmapTable.isEmpty())
       
   477         cmapTable = generateTrueTypeCMap(fontEngine);
       
   478     addBlock(QFontEngineQPF::CMapBlock, cmapTable);
       
   479 }
       
   480 
       
   481 void QPF::addGlyphs(QFontEngine *fe, const QList<CharacterRange> &ranges)
       
   482 {
       
   483     const quint16 glyphCount = fe->glyphCount();
       
   484 
       
   485     QByteArray gmap;
       
   486     gmap.resize(glyphCount * sizeof(quint32));
       
   487     gmap.fill(char(0xff));
       
   488     //qDebug() << "glyphCount" << glyphCount;
       
   489 
       
   490     QByteArray glyphs;
       
   491     if (options & RenderGlyphs) {
       
   492         // this is only a rough estimation
       
   493         glyphs.reserve(glyphCount 
       
   494                 * (sizeof(QFontEngineQPF::Glyph) 
       
   495                     + qRound(fe->maxCharWidth() * (fe->ascent() + fe->descent()).toReal())));
       
   496 
       
   497         QGlyphLayoutArray<10> layout;
       
   498 
       
   499         foreach (CharacterRange range, ranges) {
       
   500             if (debugVerbosity > 2)
       
   501                 qDebug() << "rendering range from" << range.start << "to" << range.end;
       
   502             for (uint uc = range.start; uc < range.end; ++uc) {
       
   503                 QChar ch(uc);
       
   504                 int nglyphs = 10;
       
   505                 if (!fe->stringToCMap(&ch, 1, &layout, &nglyphs, /*flags*/ 0))
       
   506                     continue;
       
   507 
       
   508                 if (nglyphs != 1)
       
   509                     continue;
       
   510 
       
   511                 const quint32 glyphIndex = layout.glyphs[0];
       
   512 
       
   513                 if (!glyphIndex)
       
   514                     continue;
       
   515 
       
   516                 Q_ASSERT(glyphIndex < glyphCount);
       
   517 
       
   518                 QImage img = fe->alphaMapForGlyph(glyphIndex).convertToFormat(QImage::Format_Indexed8);
       
   519                 glyph_metrics_t metrics = fe->boundingBox(glyphIndex);
       
   520 
       
   521                 const quint32 oldSize = glyphs.size();
       
   522                 glyphs.resize(glyphs.size() + sizeof(QFontEngineQPF::Glyph) + img.numBytes());
       
   523                 uchar *data = reinterpret_cast<uchar *>(glyphs.data() + oldSize);
       
   524 
       
   525                 uchar *gmapPtr = reinterpret_cast<uchar *>(gmap.data() + glyphIndex * sizeof(quint32));
       
   526                 qToBigEndian(oldSize, gmapPtr);
       
   527 
       
   528                 QFontEngineQPF::Glyph *glyph = reinterpret_cast<QFontEngineQPF::Glyph *>(data);
       
   529                 glyph->width = img.width();
       
   530                 glyph->height = img.height();
       
   531                 glyph->bytesPerLine = img.bytesPerLine();
       
   532                 glyph->x = qRound(metrics.x);
       
   533                 glyph->y = qRound(metrics.y);
       
   534                 glyph->advance = qRound(metrics.xoff);
       
   535                 data += sizeof(QFontEngineQPF::Glyph);
       
   536 
       
   537                 if (debugVerbosity && uc >= 'A' && uc <= 'z' || debugVerbosity > 1) {
       
   538                     qDebug() << "adding glyph with index" << glyphIndex << " uc =" << char(uc) << ":\n"
       
   539                         << "    glyph->x =" << glyph->x << "rounded from" << metrics.x << "\n"
       
   540                         << "    glyph->y =" << glyph->y << "rounded from" << metrics.y << "\n"
       
   541                         << "    width =" << glyph->width << "height =" << glyph->height
       
   542                         << "    advance =" << glyph->advance << "rounded from" << metrics.xoff
       
   543                         ;
       
   544                 }
       
   545 
       
   546                 qMemCopy(data, img.bits(), img.numBytes());
       
   547             }
       
   548         }
       
   549     }
       
   550 
       
   551     addBlock(QFontEngineQPF::GMapBlock, gmap);
       
   552     addBlock(QFontEngineQPF::GlyphBlock, glyphs);
       
   553 }
       
   554 
       
   555 void QPF::addBlock(QFontEngineQPF::BlockTag tag, const QByteArray &blockData)
       
   556 {
       
   557     addUInt16(tag);
       
   558     addUInt16(0); // padding
       
   559     const int padSize = ((blockData.size() + 3) / 4) * 4 - blockData.size();
       
   560     addUInt32(blockData.size() + padSize);
       
   561     addByteArray(blockData);
       
   562     for (int i = 0; i < padSize; ++i)
       
   563         addUInt8(0);
       
   564 }
       
   565 
       
   566 #define ADD_TAGGED_DATA(tag, qtype, type, value) \
       
   567     addUInt16(tag); \
       
   568     addUInt16(sizeof(qtype)); \
       
   569     add##type(value)
       
   570 
       
   571 void QPF::addTaggedString(QFontEngineQPF::HeaderTag tag, const QByteArray &string)
       
   572 {
       
   573     addUInt16(tag);
       
   574     addUInt16(string.length());
       
   575     addByteArray(string);
       
   576 }
       
   577 
       
   578 void QPF::addTaggedQFixed(QFontEngineQPF::HeaderTag tag, QFixed value)
       
   579 {
       
   580     ADD_TAGGED_DATA(tag, quint32, UInt32, value.value());
       
   581 }
       
   582 
       
   583 void QPF::addTaggedUInt8(QFontEngineQPF::HeaderTag tag, quint8 value)
       
   584 {
       
   585     ADD_TAGGED_DATA(tag, quint8, UInt8, value);
       
   586 }
       
   587 
       
   588 void QPF::addTaggedInt8(QFontEngineQPF::HeaderTag tag, qint8 value)
       
   589 {
       
   590     ADD_TAGGED_DATA(tag, qint8, Int8, value);
       
   591 }
       
   592 
       
   593 void QPF::addTaggedUInt16(QFontEngineQPF::HeaderTag tag, quint16 value)
       
   594 {
       
   595     ADD_TAGGED_DATA(tag, quint16, UInt16, value);
       
   596 }
       
   597 
       
   598 void QPF::addTaggedUInt32(QFontEngineQPF::HeaderTag tag, quint32 value)
       
   599 {
       
   600     ADD_TAGGED_DATA(tag, quint32, UInt32, value);
       
   601 }
       
   602 
       
   603 void QPF::dump(const QByteArray &qpf)
       
   604 {
       
   605     QPF font;
       
   606     font.qpf = qpf;
       
   607 
       
   608     const uchar *data = reinterpret_cast<const uchar *>(qpf.constData());
       
   609     const uchar *endPtr = reinterpret_cast<const uchar *>(qpf.constData() + qpf.size());
       
   610     data = font.dumpHeader(data);
       
   611 
       
   612     const quint32 *gmap = 0;
       
   613     quint32 glyphCount = 0;
       
   614 
       
   615     while (data < endPtr) {
       
   616         const QFontEngineQPF::Block *block = reinterpret_cast<const QFontEngineQPF::Block *>(data);
       
   617         quint32 tag = qFromBigEndian(block->tag);
       
   618         quint32 blockSize = qFromBigEndian(block->dataSize);
       
   619         qDebug() << "Block: Tag =" << qFromBigEndian(block->tag) << "; Size =" << blockSize << "; Offset =" << hex << data - reinterpret_cast<const uchar *>(qpf.constData());
       
   620         data += sizeof(QFontEngineQPF::Block);
       
   621 
       
   622         if (debugVerbosity) {
       
   623             if (tag == QFontEngineQPF::GMapBlock) {
       
   624                 gmap = reinterpret_cast<const quint32 *>(data);
       
   625                 glyphCount = blockSize / 4;
       
   626                 font.dumpGMapBlock(gmap, glyphCount);
       
   627             } else if (tag == QFontEngineQPF::GlyphBlock
       
   628                        && gmap && debugVerbosity > 1) {
       
   629                 font.dumpGlyphBlock(gmap, glyphCount, data, data + blockSize);
       
   630             }
       
   631         }
       
   632 
       
   633         data += blockSize;
       
   634     }
       
   635 }
       
   636 
       
   637 const uchar *QPF::dumpHeader(const uchar *data)
       
   638 {
       
   639     const QFontEngineQPF::Header *header = reinterpret_cast<const QFontEngineQPF::Header *>(data);
       
   640     qDebug() << "Header:";
       
   641     qDebug() << "magic =" 
       
   642              << header->magic[0]
       
   643              << header->magic[1]
       
   644              << header->magic[2]
       
   645              << header->magic[3];
       
   646     qDebug() << "lock =" << qFromBigEndian(header->lock);
       
   647     qDebug() << "majorVersion =" << header->majorVersion;
       
   648     qDebug() << "minorVersion =" << header->minorVersion;
       
   649     qDebug() << "dataSize =" << qFromBigEndian(header->dataSize);
       
   650 
       
   651     data += sizeof(QFontEngineQPF::Header);
       
   652 
       
   653     const uchar *endPtr = data + qFromBigEndian(header->dataSize);
       
   654 
       
   655     while (data && data < endPtr) {
       
   656         data = dumpHeaderTag(data);
       
   657     }
       
   658 
       
   659     return endPtr;
       
   660 }
       
   661 
       
   662 const uchar *QPF::dumpHeaderTag(const uchar *data)
       
   663 {
       
   664     const QFontEngineQPF::Tag *tagPtr = reinterpret_cast<const QFontEngineQPF::Tag *>(data);
       
   665     quint16 tag = qFromBigEndian(tagPtr->tag);
       
   666     quint16 size = qFromBigEndian(tagPtr->size);
       
   667 
       
   668     qDebug() << "Tag =" << tag << headerTagNames[tag];
       
   669     qDebug() << "Size =" << size;
       
   670 
       
   671     if (tag == QFontEngineQPF::Tag_EndOfHeader)
       
   672         return 0;
       
   673 
       
   674     data += sizeof(QFontEngineQPF::Tag);
       
   675 
       
   676     Q_ASSERT(tag < QFontEngineQPF::NumTags);
       
   677 
       
   678     switch (tagTypes[tag]) {
       
   679         case QFontEngineQPF::StringType:
       
   680             qDebug() << "Payload =" << QString::fromUtf8(QByteArray(reinterpret_cast<const char *>(data), size));
       
   681             break;
       
   682         case QFontEngineQPF::FixedType:
       
   683             Q_ASSERT(size == sizeof(quint32));
       
   684             qDebug() << "Payload =" << QFixed::fromFixed(qFromBigEndian<quint32>(data)).toReal();
       
   685             break;
       
   686         case QFontEngineQPF::UInt8Type:
       
   687             Q_ASSERT(size == sizeof(quint8));
       
   688             qDebug() << "Payload =" << *data;
       
   689             break;
       
   690         case QFontEngineQPF::UInt32Type:
       
   691             Q_ASSERT(size == sizeof(quint32));
       
   692             qDebug() << "Payload =" << qFromBigEndian<quint32>(data);
       
   693             break;
       
   694         case QFontEngineQPF::BitFieldType: {
       
   695             QByteArray bits(reinterpret_cast<const char *>(data), size);
       
   696             qDebug() << "Payload =" << stringify(bits);
       
   697             if (QPF::debugVerbosity > 2 && tag == QFontEngineQPF::Tag_WritingSystems)
       
   698                 dumpWritingSystems(bits);
       
   699             } break;
       
   700     }
       
   701 
       
   702     data += size;
       
   703     return data;
       
   704 }
       
   705 
       
   706 void QPF::dumpGMapBlock(const quint32 *gmap, int glyphCount)
       
   707 {
       
   708     qDebug() << "glyphCount =" << glyphCount;
       
   709     int renderedGlyphs = 0;
       
   710     for (int i = 0; i < glyphCount; ++i) {
       
   711         if (gmap[i] != 0xffffffff) {
       
   712             const quint32 glyphPos = qFromBigEndian(gmap[i]);
       
   713             qDebug("gmap[%d] = 0x%x / %u", i, glyphPos, glyphPos);
       
   714             ++renderedGlyphs;
       
   715         }
       
   716     }
       
   717     qDebug() << "Glyphs rendered:" << renderedGlyphs << "; Glyphs missing from the font:" << glyphCount - renderedGlyphs;
       
   718 }
       
   719 
       
   720 void QPF::dumpGlyphBlock(const quint32 *gmap, int glyphCount, const uchar *data, const uchar *endPtr)
       
   721 {
       
   722     // glyphPos -> glyphIndex
       
   723     QMap<quint32, quint32> reverseGlyphMap;
       
   724     for (int i = 0; i < glyphCount; ++i) {
       
   725         if (gmap[i] == 0xffffffff)
       
   726             continue;
       
   727         const quint32 glyphPos = qFromBigEndian(gmap[i]);
       
   728         reverseGlyphMap[glyphPos] = i;
       
   729     }
       
   730 
       
   731     const uchar *glyphBlockBegin = data;
       
   732     while (data < endPtr) {
       
   733         const QFontEngineQPF::Glyph *g = reinterpret_cast<const QFontEngineQPF::Glyph *>(data);
       
   734 
       
   735         const quint64 glyphOffset = data - glyphBlockBegin;
       
   736         const quint32 glyphIndex = reverseGlyphMap.value(glyphOffset, 0xffffffff);
       
   737 
       
   738         if (glyphIndex == 0xffffffff)
       
   739             qDebug() << "############: Glyph present in glyph block is not listed in glyph map!";
       
   740         qDebug("glyph at offset 0x%x glyphIndex = %u", quint32(glyphOffset), glyphIndex);
       
   741         qDebug() << "    width =" << g->width << "height =" << g->height << "x =" << g->x << "y =" << g->y;
       
   742         qDebug() << "    advance =" << g->advance << "bytesPerLine =" << g->bytesPerLine;
       
   743 
       
   744         data += sizeof(*g);
       
   745         if (glyphIndex == 0xffffffff || debugVerbosity > 4) {
       
   746             dumpGlyph(data, g);
       
   747         }
       
   748 
       
   749         data += g->height * g->bytesPerLine;
       
   750     }
       
   751 }
       
   752 
       
   753 void QPF::dumpGlyph(const uchar *data, const QFontEngineQPF::Glyph *glyph)
       
   754 {
       
   755     fprintf(stderr, "---- glyph data:\n");
       
   756     const char *alphas = " .o#";
       
   757     for (int y = 0; y < glyph->height; ++y) {
       
   758         for (int x = 0; x < glyph->width; ++x) {
       
   759             const uchar value = data[y * glyph->bytesPerLine + x];
       
   760             fprintf(stderr, "%c", alphas[value >> 6]);
       
   761         }
       
   762         fprintf(stderr, "\n");
       
   763     }
       
   764     fprintf(stderr, "----\n");
       
   765 }
       
   766 
       
   767 QT_END_NAMESPACE