1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the tools applications of the Qt Toolkit.
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
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.
40 ****************************************************************************/
45 #include <private/qfontengine_p.h>
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] = {
109 // SimplifiedChinese,
111 // TraditionalChinese,
118 { 0, 127 }, // same as latin1
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;
134 for(i
= 0; i
< QFontDatabase::WritingSystemsCount
; i
++) {
135 int bit
= requiredUnicodeBits
[i
][0];
137 int flag
= 1 << (bit
&31);
138 if (bit
!= 126 && unicodeRange
[index
] & flag
) {
139 bit
= requiredUnicodeBits
[i
][1];
142 flag
= 1 << (bit
&31);
143 if (bit
== 127 || unicodeRange
[index
] & flag
) {
144 writingSystems
.append(QFontDatabase::WritingSystem(i
));
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
);
153 //qDebug("font %s supports Simplified Chinese", familyName.latin1());
155 if(codePageRange
[0] & (1 << TraditionalChineseCsbBit
)) {
156 writingSystems
.append(QFontDatabase::TraditionalChinese
);
158 //qDebug("font %s supports Traditional Chinese", familyName.latin1());
160 if(codePageRange
[0] & (1 << JapaneseCsbBit
)) {
161 writingSystems
.append(QFontDatabase::Japanese
);
163 //qDebug("font %s supports Japanese", familyName.latin1());
165 if(codePageRange
[0] & (1 << KoreanCsbBit
)) {
166 writingSystems
.append(QFontDatabase::Korean
);
168 //qDebug("font %s supports Korean", familyName.latin1());
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())
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));
203 static QString
stringify(const QByteArray
&bits
)
206 for (int i
= 0; i
< bits
.count(); ++i
) {
207 uchar currentByte
= bits
.at(i
);
208 for (int j
= 0; j
< 8; ++j
) {
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
] = {
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" : "")
262 fileName
.replace(QLatin1Char(' '), QLatin1Char('_'));
266 QByteArray
QPF::generate(const QFont
&font
, int options
, const QList
<CharacterRange
> &ranges
, QString
*originalFontFile
)
268 QTextEngine
engine("Test", font
);
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
)
285 font
.options
= options
;
286 font
.addHeader(fontEngine
);
287 if (options
& IncludeCMap
)
288 font
.addCMap(fontEngine
);
289 font
.addGlyphs(fontEngine
, ranges
);
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;
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());
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)))
361 int start
; // codepoints
366 static QByteArray
generateTrueTypeCMap(QFontEngine
*fe
)
369 const int glyphCount
= fe
->glyphCount();
374 APPEND(quint16
, 0); // table version number
375 APPEND(quint16
, 1); // number of tables
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
) {
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;
413 // entering a new segment?
414 if (validGlyph
&& (!inSegment
|| layout
.glyphs
[0] != previousGlyphIndex
+ 1)) {
415 currentSegment
.start
= uc
;
416 currentSegment
.startGlyphIndex
= layout
.glyphs
[0];
421 previousGlyphIndex
= layout
.glyphs
[0];
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
);
460 for (int i
= 0; i
< segments
.count(); ++i
)
461 APPEND(quint16
, segments
.at(i
).startGlyphIndex
- segments
.at(i
).start
);
464 for (int i
= 0; i
< segments
.count(); ++i
)
467 uchar
*lengthPtr
= reinterpret_cast<uchar
*>(cmap
.data()) + cmapTableLengthOffset
;
468 qToBigEndian
<quint16
>(cmap
.size() - cmapOffset
, lengthPtr
);
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();
486 gmap
.resize(glyphCount
* sizeof(quint32
));
487 gmap
.fill(char(0xff));
488 //qDebug() << "glyphCount" << glyphCount;
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
) {
505 if (!fe
->stringToCMap(&ch
, 1, &layout
, &nglyphs
, /*flags*/ 0))
511 const quint32 glyphIndex
= layout
.glyphs
[0];
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
)
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
)
566 #define ADD_TAGGED_DATA(tag, qtype, type, value) \
568 addUInt16(sizeof(qtype)); \
571 void QPF::addTaggedString(QFontEngineQPF::HeaderTag tag
, const QByteArray
&string
)
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
)
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
);
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 ="
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
);
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
)
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
));
682 case QFontEngineQPF::FixedType
:
683 Q_ASSERT(size
== sizeof(quint32
));
684 qDebug() << "Payload =" << QFixed::fromFixed(qFromBigEndian
<quint32
>(data
)).toReal();
686 case QFontEngineQPF::UInt8Type
:
687 Q_ASSERT(size
== sizeof(quint8
));
688 qDebug() << "Payload =" << *data
;
690 case QFontEngineQPF::UInt32Type
:
691 Q_ASSERT(size
== sizeof(quint32
));
692 qDebug() << "Payload =" << qFromBigEndian
<quint32
>(data
);
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
);
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
);
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)
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
;
745 if (glyphIndex
== 0xffffffff || debugVerbosity
> 4) {
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");