Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
[qt-netbsd.git] / tools / makeqpf / qpf2.cpp
blobab57cea5bc6de0eaf0c99032ca911a8ef77bee78
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 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.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "qpf2.h"
44 #include <math.h>
45 #include <private/qfontengine_p.h>
46 #include <QFile>
47 #include <qendian.h>
49 QT_BEGIN_NAMESPACE
51 #include "../../src/gui/text/qpfutil.cpp"
53 int QPF::debugVerbosity = 0;
55 // ### copied from qfontdatabase.cpp
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 }
123 #define SimplifiedChineseCsbBit 18
124 #define TraditionalChineseCsbBit 20
125 #define JapaneseCsbBit 17
126 #define KoreanCsbBit 21
128 static QList<QFontDatabase::WritingSystem> determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2])
130 QList<QFontDatabase::WritingSystem> writingSystems;
131 bool hasScript = false;
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;
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);
150 if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) {
151 writingSystems.append(QFontDatabase::SimplifiedChinese);
152 hasScript = true;
153 //qDebug("font %s supports Simplified Chinese", familyName.latin1());
155 if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
156 writingSystems.append(QFontDatabase::TraditionalChinese);
157 hasScript = true;
158 //qDebug("font %s supports Traditional Chinese", familyName.latin1());
160 if(codePageRange[0] & (1 << JapaneseCsbBit)) {
161 writingSystems.append(QFontDatabase::Japanese);
162 hasScript = true;
163 //qDebug("font %s supports Japanese", familyName.latin1());
165 if(codePageRange[0] & (1 << KoreanCsbBit)) {
166 writingSystems.append(QFontDatabase::Korean);
167 hasScript = true;
168 //qDebug("font %s supports Korean", familyName.latin1());
170 if (!hasScript)
171 writingSystems.append(QFontDatabase::Symbol);
173 return writingSystems;
176 static QByteArray getWritingSystems(QFontEngine *fontEngine)
178 QByteArray os2Table = fontEngine->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
179 if (os2Table.isEmpty())
180 return QByteArray();
182 const uchar *data = reinterpret_cast<const uchar *>(os2Table.constData());
184 quint32 unicodeRange[4] = {
185 qFromBigEndian<quint32>(data + 42),
186 qFromBigEndian<quint32>(data + 46),
187 qFromBigEndian<quint32>(data + 50),
188 qFromBigEndian<quint32>(data + 54)
190 quint32 codePageRange[2] = { qFromBigEndian<quint32>(data + 78), qFromBigEndian<quint32>(data + 82) };
191 QList<QFontDatabase::WritingSystem> systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
193 QByteArray bitField((QFontDatabase::WritingSystemsCount + 7) / 8, 0);
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));
200 return bitField;
203 static QString stringify(const QByteArray &bits)
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;
216 return result;
219 static void dumpWritingSystems(const QByteArray &bits)
221 QStringList writingSystems;
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));
229 qDebug() << "Supported writing systems:" << writingSystems;
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"
256 QString QPF::fileNameForFont(const QFont &f)
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;
266 QByteArray QPF::generate(const QFont &font, int options, const QList<CharacterRange> &ranges, QString *originalFontFile)
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);
275 if (originalFontFile)
276 *originalFontFile = QFile::decodeName(fontEngine->faceId().filename);
278 return generate(fontEngine, options, ranges);
281 QByteArray QPF::generate(QFontEngine *fontEngine, int options, const QList<CharacterRange> &ranges)
283 QPF font;
285 font.options = options;
286 font.addHeader(fontEngine);
287 if (options & IncludeCMap)
288 font.addCMap(fontEngine);
289 font.addGlyphs(fontEngine, ranges);
291 return font.qpf;
294 void QPF::addHeader(QFontEngine *fontEngine)
296 QFontEngineQPF::Header *header = reinterpret_cast<QFontEngineQPF::Header *>(addBytes(sizeof(QFontEngineQPF::Header)));
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();
311 addTaggedString(QFontEngineQPF::Tag_FontName, fontEngine->fontDef.family.toUtf8());
313 QFontEngine::FaceId face = fontEngine->faceId();
314 addTaggedString(QFontEngineQPF::Tag_FileName, face.filename);
315 addTaggedUInt32(QFontEngineQPF::Tag_FileIndex, face.index);
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);
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);
337 QByteArray writingSystemBitField = getWritingSystems(fontEngine);
338 if (!writingSystemBitField.isEmpty())
339 addTaggedString(QFontEngineQPF::Tag_WritingSystems, writingSystemBitField);
341 addTaggedUInt8(QFontEngineQPF::Tag_GlyphFormat, QFontEngineQPF::AlphamapGlyphs);
343 addTaggedString(QFontEngineQPF::Tag_EndOfHeader, QByteArray());
344 align4();
345 header = reinterpret_cast<QFontEngineQPF::Header *>(qpf.data());
346 header->dataSize = qToBigEndian<quint16>(qpf.size() - oldSize);
349 static uchar *appendBytes(QByteArray &array, int size)
351 int oldSize = array.size();
352 array.resize(array.size() + size);
353 return reinterpret_cast<uchar *>(array.data() + oldSize);
356 #define APPEND(type, value) \
357 qToBigEndian<type>(value, appendBytes(cmap, sizeof(type)))
359 struct CMapSegment
361 int start; // codepoints
362 int end;
363 int startGlyphIndex;
366 static QByteArray generateTrueTypeCMap(QFontEngine *fe)
368 QByteArray cmap;
369 const int glyphCount = fe->glyphCount();
370 if (!glyphCount)
371 return cmap;
373 // cmap header
374 APPEND(quint16, 0); // table version number
375 APPEND(quint16, 1); // number of tables
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
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
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;
396 QGlyphLayoutArray<10> layout;
397 for (uint uc = 0; uc < 0x10000; ++uc) {
398 QChar ch(uc);
399 int nglyphs = 10;
401 bool validGlyph = fe->stringToCMap(&ch, 1, &layout, &nglyphs, /*flags*/ 0)
402 && nglyphs == 1 && layout.glyphs[0];
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;
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;
420 if (validGlyph)
421 previousGlyphIndex = layout.glyphs[0];
422 else
423 previousGlyphIndex = 0xfffffffe;
426 currentSegment.start = 0xffff;
427 currentSegment.end = 0xffff;
428 currentSegment.startGlyphIndex = 0;
429 segments.append(currentSegment);
431 if (QPF::debugVerbosity > 3)
432 qDebug() << "segments:" << segments.count();
434 Q_ASSERT(!inSegment);
436 const quint16 entrySelector = int(log2(segments.count()));
437 const quint16 searchRange = 2 * (1 << entrySelector);
438 const quint16 rangeShift = segments.count() * 2 - searchRange;
440 if (QPF::debugVerbosity > 3)
441 qDebug() << "entrySelector" << entrySelector << "searchRange" << searchRange
442 << "rangeShift" << rangeShift;
444 APPEND(quint16, segments.count() * 2); // segCountX2
445 APPEND(quint16, searchRange);
446 APPEND(quint16, entrySelector);
447 APPEND(quint16, rangeShift);
449 // end character codes
450 for (int i = 0; i < segments.count(); ++i)
451 APPEND(quint16, segments.at(i).end);
453 APPEND(quint16, 0); // pad
455 // start character codes
456 for (int i = 0; i < segments.count(); ++i)
457 APPEND(quint16, segments.at(i).start);
459 // id deltas
460 for (int i = 0; i < segments.count(); ++i)
461 APPEND(quint16, segments.at(i).startGlyphIndex - segments.at(i).start);
463 // id range offsets
464 for (int i = 0; i < segments.count(); ++i)
465 APPEND(quint16, 0);
467 uchar *lengthPtr = reinterpret_cast<uchar *>(cmap.data()) + cmapTableLengthOffset;
468 qToBigEndian<quint16>(cmap.size() - cmapOffset, lengthPtr);
470 return cmap;
473 void QPF::addCMap(QFontEngine *fontEngine)
475 QByteArray cmapTable = fontEngine->getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
476 if (cmapTable.isEmpty())
477 cmapTable = generateTrueTypeCMap(fontEngine);
478 addBlock(QFontEngineQPF::CMapBlock, cmapTable);
481 void QPF::addGlyphs(QFontEngine *fe, const QList<CharacterRange> &ranges)
483 const quint16 glyphCount = fe->glyphCount();
485 QByteArray gmap;
486 gmap.resize(glyphCount * sizeof(quint32));
487 gmap.fill(char(0xff));
488 //qDebug() << "glyphCount" << glyphCount;
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())));
497 QGlyphLayoutArray<10> layout;
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;
508 if (nglyphs != 1)
509 continue;
511 const quint32 glyphIndex = layout.glyphs[0];
513 if (!glyphIndex)
514 continue;
516 Q_ASSERT(glyphIndex < glyphCount);
518 QImage img = fe->alphaMapForGlyph(glyphIndex).convertToFormat(QImage::Format_Indexed8);
519 glyph_metrics_t metrics = fe->boundingBox(glyphIndex);
521 const quint32 oldSize = glyphs.size();
522 glyphs.resize(glyphs.size() + sizeof(QFontEngineQPF::Glyph) + img.byteCount());
523 uchar *data = reinterpret_cast<uchar *>(glyphs.data() + oldSize);
525 uchar *gmapPtr = reinterpret_cast<uchar *>(gmap.data() + glyphIndex * sizeof(quint32));
526 qToBigEndian(oldSize, gmapPtr);
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);
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
546 qMemCopy(data, img.bits(), img.byteCount());
551 addBlock(QFontEngineQPF::GMapBlock, gmap);
552 addBlock(QFontEngineQPF::GlyphBlock, glyphs);
555 void QPF::addBlock(QFontEngineQPF::BlockTag tag, const QByteArray &blockData)
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);
566 #define ADD_TAGGED_DATA(tag, qtype, type, value) \
567 addUInt16(tag); \
568 addUInt16(sizeof(qtype)); \
569 add##type(value)
571 void QPF::addTaggedString(QFontEngineQPF::HeaderTag tag, const QByteArray &string)
573 addUInt16(tag);
574 addUInt16(string.length());
575 addByteArray(string);
578 void QPF::addTaggedQFixed(QFontEngineQPF::HeaderTag tag, QFixed value)
580 ADD_TAGGED_DATA(tag, quint32, UInt32, value.value());
583 void QPF::addTaggedUInt8(QFontEngineQPF::HeaderTag tag, quint8 value)
585 ADD_TAGGED_DATA(tag, quint8, UInt8, value);
588 void QPF::addTaggedInt8(QFontEngineQPF::HeaderTag tag, qint8 value)
590 ADD_TAGGED_DATA(tag, qint8, Int8, value);
593 void QPF::addTaggedUInt16(QFontEngineQPF::HeaderTag tag, quint16 value)
595 ADD_TAGGED_DATA(tag, quint16, UInt16, value);
598 void QPF::addTaggedUInt32(QFontEngineQPF::HeaderTag tag, quint32 value)
600 ADD_TAGGED_DATA(tag, quint32, UInt32, value);
603 void QPF::dump(const QByteArray &qpf)
605 QPF font;
606 font.qpf = qpf;
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);
612 const quint32 *gmap = 0;
613 quint32 glyphCount = 0;
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);
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);
633 data += blockSize;
637 const uchar *QPF::dumpHeader(const uchar *data)
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);
651 data += sizeof(QFontEngineQPF::Header);
653 const uchar *endPtr = data + qFromBigEndian(header->dataSize);
655 while (data && data < endPtr) {
656 data = dumpHeaderTag(data);
659 return endPtr;
662 const uchar *QPF::dumpHeaderTag(const uchar *data)
664 const QFontEngineQPF::Tag *tagPtr = reinterpret_cast<const QFontEngineQPF::Tag *>(data);
665 quint16 tag = qFromBigEndian(tagPtr->tag);
666 quint16 size = qFromBigEndian(tagPtr->size);
668 qDebug() << "Tag =" << tag << headerTagNames[tag];
669 qDebug() << "Size =" << size;
671 if (tag == QFontEngineQPF::Tag_EndOfHeader)
672 return 0;
674 data += sizeof(QFontEngineQPF::Tag);
676 Q_ASSERT(tag < QFontEngineQPF::NumTags);
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;
702 data += size;
703 return data;
706 void QPF::dumpGMapBlock(const quint32 *gmap, int glyphCount)
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;
717 qDebug() << "Glyphs rendered:" << renderedGlyphs << "; Glyphs missing from the font:" << glyphCount - renderedGlyphs;
720 void QPF::dumpGlyphBlock(const quint32 *gmap, int glyphCount, const uchar *data, const uchar *endPtr)
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;
731 const uchar *glyphBlockBegin = data;
732 while (data < endPtr) {
733 const QFontEngineQPF::Glyph *g = reinterpret_cast<const QFontEngineQPF::Glyph *>(data);
735 const quint64 glyphOffset = data - glyphBlockBegin;
736 const quint32 glyphIndex = reverseGlyphMap.value(glyphOffset, 0xffffffff);
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;
744 data += sizeof(*g);
745 if (glyphIndex == 0xffffffff || debugVerbosity > 4) {
746 dumpGlyph(data, g);
749 data += g->height * g->bytesPerLine;
753 void QPF::dumpGlyph(const uchar *data, const QFontEngineQPF::Glyph *glyph)
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]);
762 fprintf(stderr, "\n");
764 fprintf(stderr, "----\n");
767 QT_END_NAMESPACE