Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
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
49QT_BEGIN_NAMESPACE
50
51#include "../../src/gui/text/qpfutil.cpp"
52
53int QPF::debugVerbosity = 0;
54
55// ### copied from qfontdatabase.cpp
56
57// see the Unicode subset bitfields in the MSDN docs
58static 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
128static 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
176static 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
203static 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
219static 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
232static 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
256QString 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
266QByteArray 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
281QByteArray 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
294void 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
349static 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
359struct CMapSegment
360{
361 int start; // codepoints
362 int end;
363 int startGlyphIndex;
364};
365
366static 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
473void 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
481void 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.byteCount());
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 memcpy(data, img.bits(), img.byteCount());
547 }
548 }
549 }
550
551 addBlock(QFontEngineQPF::GMapBlock, gmap);
552 addBlock(QFontEngineQPF::GlyphBlock, glyphs);
553}
554
555void 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
571void QPF::addTaggedString(QFontEngineQPF::HeaderTag tag, const QByteArray &string)
572{
573 addUInt16(tag);
574 addUInt16(string.length());
575 addByteArray(string);
576}
577
578void QPF::addTaggedQFixed(QFontEngineQPF::HeaderTag tag, QFixed value)
579{
580 ADD_TAGGED_DATA(tag, quint32, UInt32, value.value());
581}
582
583void QPF::addTaggedUInt8(QFontEngineQPF::HeaderTag tag, quint8 value)
584{
585 ADD_TAGGED_DATA(tag, quint8, UInt8, value);
586}
587
588void QPF::addTaggedInt8(QFontEngineQPF::HeaderTag tag, qint8 value)
589{
590 ADD_TAGGED_DATA(tag, qint8, Int8, value);
591}
592
593void QPF::addTaggedUInt16(QFontEngineQPF::HeaderTag tag, quint16 value)
594{
595 ADD_TAGGED_DATA(tag, quint16, UInt16, value);
596}
597
598void QPF::addTaggedUInt32(QFontEngineQPF::HeaderTag tag, quint32 value)
599{
600 ADD_TAGGED_DATA(tag, quint32, UInt32, value);
601}
602
603void 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
637const 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
662const 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
706void 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
720void 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
753void 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
767QT_END_NAMESPACE
768

Warning: That file was not part of the compilation database. It may have many parsing errors.