1 /****************************************************************************
3 ** Copyright (C) 2011 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 QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qfontengine_qpa_p.h"
44 #include <QtCore/QFile>
45 #include <QtCore/QFileInfo>
46 #include <QtCore/QDir>
47 #include <QtCore/QBuffer>
49 #include <QtGui/private/qapplication_p.h>
50 #include <QtGui/QPlatformFontDatabase>
51 #include <QtGui/private/qpaintengine_raster_p.h>
55 //#define DEBUG_HEADER
56 //#define DEBUG_FONTENGINE
58 static QFontEngineQPA::TagType tagTypes[QFontEngineQPA::NumTags] = {
59 QFontEngineQPA::StringType, // FontName
60 QFontEngineQPA::StringType, // FileName
61 QFontEngineQPA::UInt32Type, // FileIndex
62 QFontEngineQPA::UInt32Type, // FontRevision
63 QFontEngineQPA::StringType, // FreeText
64 QFontEngineQPA::FixedType, // Ascent
65 QFontEngineQPA::FixedType, // Descent
66 QFontEngineQPA::FixedType, // Leading
67 QFontEngineQPA::FixedType, // XHeight
68 QFontEngineQPA::FixedType, // AverageCharWidth
69 QFontEngineQPA::FixedType, // MaxCharWidth
70 QFontEngineQPA::FixedType, // LineThickness
71 QFontEngineQPA::FixedType, // MinLeftBearing
72 QFontEngineQPA::FixedType, // MinRightBearing
73 QFontEngineQPA::FixedType, // UnderlinePosition
74 QFontEngineQPA::UInt8Type, // GlyphFormat
75 QFontEngineQPA::UInt8Type, // PixelSize
76 QFontEngineQPA::UInt8Type, // Weight
77 QFontEngineQPA::UInt8Type, // Style
78 QFontEngineQPA::StringType, // EndOfHeader
79 QFontEngineQPA::BitFieldType// WritingSystems
83 #if defined(DEBUG_HEADER)
84 # define DEBUG_VERIFY qDebug
86 # define DEBUG_VERIFY if (0) qDebug
89 #define READ_VERIFY(type, variable) \
90 if (tagPtr + sizeof(type) > endPtr) { \
91 DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \
94 variable = qFromBigEndian<type>(tagPtr); \
95 DEBUG_VERIFY() << "read value" << variable << "of type " #type; \
96 tagPtr += sizeof(type)
99 T readValue(const uchar *&data)
101 T value = qFromBigEndian<T>(data);
106 #define VERIFY(condition) \
107 if (!(condition)) { \
108 DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \
112 #define VERIFY_TAG(condition) \
113 if (!(condition)) { \
114 DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \
118 static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr)
121 READ_VERIFY(quint16, tag);
122 READ_VERIFY(quint16, length);
123 if (tag == QFontEngineQPA::Tag_EndOfHeader)
125 if (tag < QFontEngineQPA::NumTags) {
126 switch (tagTypes[tag]) {
127 case QFontEngineQPA::BitFieldType:
128 case QFontEngineQPA::StringType:
129 // can't do anything...
131 case QFontEngineQPA::UInt32Type:
132 VERIFY_TAG(length == sizeof(quint32));
134 case QFontEngineQPA::FixedType:
135 VERIFY_TAG(length == sizeof(quint32));
137 case QFontEngineQPA::UInt8Type:
138 VERIFY_TAG(length == sizeof(quint8));
141 #if defined(DEBUG_HEADER)
143 qDebug() << "tag data" << hex << *tagPtr;
144 else if (length == 4)
145 qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
148 return tagPtr + length;
151 const QFontEngineQPA::Glyph *QFontEngineQPA::findGlyph(glyph_t g) const
153 if (!g || g >= glyphMapEntries)
155 const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
156 quint32 glyphPos = qFromBigEndian<quint32>(gmapPtr[g]);
157 if (glyphPos > glyphDataSize) {
158 if (glyphPos == 0xffffffff)
160 #if defined(DEBUG_FONTENGINE)
161 qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
163 if (glyphPos > glyphDataSize)
166 return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
169 bool QFontEngineQPA::verifyHeader(const uchar *data, int size)
171 VERIFY(size >= int(sizeof(Header)));
172 const Header *header = reinterpret_cast<const Header *>(data);
173 if (header->magic[0] != 'Q'
174 || header->magic[1] != 'P'
175 || header->magic[2] != 'F'
176 || header->magic[3] != '2')
179 VERIFY(header->majorVersion <= CurrentMajorVersion);
180 const quint16 dataSize = qFromBigEndian<quint16>(header->dataSize);
181 VERIFY(size >= int(sizeof(Header)) + dataSize);
183 const uchar *tagPtr = data + sizeof(Header);
184 const uchar *tagEndPtr = tagPtr + dataSize;
185 while (tagPtr < tagEndPtr - 3) {
186 tagPtr = verifyTag(tagPtr, tagEndPtr);
190 VERIFY(tagPtr <= tagEndPtr);
194 QVariant QFontEngineQPA::extractHeaderField(const uchar *data, HeaderTag requestedTag)
196 const Header *header = reinterpret_cast<const Header *>(data);
197 const uchar *tagPtr = data + sizeof(Header);
198 const uchar *endPtr = tagPtr + qFromBigEndian<quint16>(header->dataSize);
199 while (tagPtr < endPtr - 3) {
200 quint16 tag = readValue<quint16>(tagPtr);
201 quint16 length = readValue<quint16>(tagPtr);
202 if (tag == requestedTag) {
203 switch (tagTypes[requestedTag]) {
205 return QVariant(QString::fromUtf8(reinterpret_cast<const char *>(tagPtr), length));
207 return QVariant(readValue<quint32>(tagPtr));
209 return QVariant(uint(*tagPtr));
211 return QVariant(QFixed::fromFixed(readValue<quint32>(tagPtr)).toReal());
213 return QVariant(QByteArray(reinterpret_cast<const char *>(tagPtr), length));
216 } else if (tag == Tag_EndOfHeader) {
227 static inline unsigned int getChar(const QChar *str, int &i, const int len)
229 unsigned int uc = str[i].unicode();
230 if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
231 uint low = str[i+1].unicode();
232 if (low >= 0xdc00 && low < 0xe000) {
233 uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
240 QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
241 : fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
252 kerning_pairs_loaded = false;
255 #if defined(DEBUG_FONTENGINE)
256 qDebug() << "QFontEngineQPA::QFontEngineQPA( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
259 if (!verifyHeader(fontData, dataSize)) {
260 #if defined(DEBUG_FONTENGINE)
261 qDebug() << "verifyHeader failed!";
266 const Header *header = reinterpret_cast<const Header *>(fontData);
268 readOnly = (header->lock == 0xffffffff);
270 const uchar *imgData = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize);
271 const uchar *endPtr = fontData + dataSize;
272 while (imgData <= endPtr - 8) {
273 quint16 blockTag = readValue<quint16>(imgData);
274 imgData += 2; // skip padding
275 quint32 blockSize = readValue<quint32>(imgData);
277 if (blockTag == CMapBlock) {
278 cmapOffset = imgData - fontData;
279 cmapSize = blockSize;
280 } else if (blockTag == GMapBlock) {
281 glyphMapOffset = imgData - fontData;
282 glyphMapEntries = blockSize / 4;
283 } else if (blockTag == GlyphBlock) {
284 glyphDataOffset = imgData - fontData;
285 glyphDataSize = blockSize;
288 imgData += blockSize;
291 face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
292 face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
296 int tableSize = cmapSize;
297 const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
299 cmapOffset = cmapPtr - fontData;
302 } else if (externalCMap) {
303 int tableSize = cmapSize;
304 externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
307 // verify all the positions in the glyphMap
308 if (glyphMapOffset) {
309 const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
310 for (uint i = 0; i < glyphMapEntries; ++i) {
311 quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]);
312 if (glyphDataPos == 0xffffffff)
314 if (glyphDataPos >= glyphDataSize) {
323 #if defined(DEBUG_FONTENGINE)
325 qDebug() << "fontData" << fontData << "dataSize" << dataSize
326 << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
327 << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
328 << "fd" << fd << "glyphDataSize" << glyphDataSize;
332 QFontEngineQPA::~QFontEngineQPA()
336 bool QFontEngineQPA::getSfntTableData(uint tag, uchar *buffer, uint *length) const
344 bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
346 if (*nglyphs < len) {
351 #if defined(DEBUG_FONTENGINE)
352 QSet<QChar> seenGlyphs;
355 const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
357 bool mirrored = flags & QTextEngine::RightToLeft;
360 for (int i = 0; i < len; ++i) {
361 unsigned int uc = getChar(str, i, len);
363 uc = QChar::mirroredChar(uc);
364 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
365 if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
366 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
370 for (int i = 0; i < len; ++i) {
371 unsigned int uc = getChar(str, i, len);
373 uc = QChar::mirroredChar(uc);
374 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
375 #if 0 && defined(DEBUG_FONTENGINE)
377 if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
378 qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
380 seenGlyphs.insert(c);
386 *nglyphs = glyph_pos;
387 glyphs->numGlyphs = glyph_pos;
388 recalcAdvances(glyphs, flags);
392 void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
394 for (int i = 0; i < glyphs->numGlyphs; ++i) {
395 const Glyph *g = findGlyph(glyphs->glyphs[i]);
397 glyphs->glyphs[i] = 0;
400 glyphs->advances_x[i] = g->advance;
401 glyphs->advances_y[i] = 0;
405 QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g)
407 const Glyph *glyph = findGlyph(g);
411 const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
413 QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8);
418 void QFontEngineQPA::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
420 addBitmapFontToPath(x, y, glyphs, path, flags);
423 glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs)
425 glyph_metrics_t overall;
426 // initialize with line height, we get the same behaviour on all platforms
427 overall.y = -ascent();
428 overall.height = ascent() + descent() + 1;
432 for (int i = 0; i < glyphs.numGlyphs; i++) {
433 const Glyph *g = findGlyph(glyphs.glyphs[i]);
437 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
438 QFixed y = overall.yoff + glyphs.offsets[i].y + g->y;
439 overall.x = qMin(overall.x, x);
440 overall.y = qMin(overall.y, y);
441 xmax = qMax(xmax, x + g->width);
442 ymax = qMax(ymax, y + g->height);
443 overall.xoff += g->advance;
445 overall.height = qMax(overall.height, ymax - overall.y);
446 overall.width = xmax - overall.x;
451 glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph)
453 glyph_metrics_t overall;
454 const Glyph *g = findGlyph(glyph);
459 overall.width = g->width;
460 overall.height = g->height;
461 overall.xoff = g->advance;
465 QFixed QFontEngineQPA::ascent() const
467 return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
470 QFixed QFontEngineQPA::descent() const
472 return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
475 QFixed QFontEngineQPA::leading() const
477 return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
480 qreal QFontEngineQPA::maxCharWidth() const
482 return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
485 qreal QFontEngineQPA::minLeftBearing() const
487 return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
490 qreal QFontEngineQPA::minRightBearing() const
492 return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
495 QFixed QFontEngineQPA::underlinePosition() const
497 return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
500 QFixed QFontEngineQPA::lineThickness() const
502 return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
505 QFontEngine::Type QFontEngineQPA::type() const
507 return QFontEngine::QPF2;
510 bool QFontEngineQPA::canRender(const QChar *string, int len)
512 const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
515 for (int i = 0; i < len; ++i) {
516 unsigned int uc = getChar(string, i, len);
517 glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
519 g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
524 for (int i = 0; i < len; ++i) {
525 unsigned int uc = getChar(string, i, len);
526 if (!getTrueTypeGlyphIndex(cmap, uc))
533 bool QFontEngineQPA::isValid() const
535 return fontData && dataSize && (cmapOffset || externalCMap)
536 && glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
539 void QPAGenerator::generate()
543 writeBlock(QFontEngineQPA::GlyphBlock, QByteArray());
545 dev->seek(4); // position of header.lock
549 void QPAGenerator::writeHeader()
551 QFontEngineQPA::Header header;
553 header.magic[0] = 'Q';
554 header.magic[1] = 'P';
555 header.magic[2] = 'F';
556 header.magic[3] = '2';
558 header.majorVersion = QFontEngineQPA::CurrentMajorVersion;
559 header.minorVersion = QFontEngineQPA::CurrentMinorVersion;
561 dev->write((const char *)&header, sizeof(header));
563 writeTaggedString(QFontEngineQPA::Tag_FontName, fe->fontDef.family.toUtf8());
565 QFontEngine::FaceId face = fe->faceId();
566 writeTaggedString(QFontEngineQPA::Tag_FileName, face.filename);
567 writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index);
572 bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
574 const quint32 revision = qFromBigEndian<quint32>(data);
575 writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision);
579 writeTaggedQFixed(QFontEngineQPA::Tag_Ascent, fe->ascent());
580 writeTaggedQFixed(QFontEngineQPA::Tag_Descent, fe->descent());
581 writeTaggedQFixed(QFontEngineQPA::Tag_Leading, fe->leading());
582 writeTaggedQFixed(QFontEngineQPA::Tag_XHeight, fe->xHeight());
583 writeTaggedQFixed(QFontEngineQPA::Tag_AverageCharWidth, fe->averageCharWidth());
584 writeTaggedQFixed(QFontEngineQPA::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth()));
585 writeTaggedQFixed(QFontEngineQPA::Tag_LineThickness, fe->lineThickness());
586 writeTaggedQFixed(QFontEngineQPA::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing()));
587 writeTaggedQFixed(QFontEngineQPA::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing()));
588 writeTaggedQFixed(QFontEngineQPA::Tag_UnderlinePosition, fe->underlinePosition());
589 writeTaggedUInt8(QFontEngineQPA::Tag_PixelSize, fe->fontDef.pixelSize);
590 writeTaggedUInt8(QFontEngineQPA::Tag_Weight, fe->fontDef.weight);
591 writeTaggedUInt8(QFontEngineQPA::Tag_Style, fe->fontDef.style);
593 writeTaggedUInt8(QFontEngineQPA::Tag_GlyphFormat, QFontEngineQPA::AlphamapGlyphs);
595 writeTaggedString(QFontEngineQPA::Tag_EndOfHeader, QByteArray());
598 const quint64 size = dev->pos();
599 header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
601 dev->write((const char *)&header, sizeof(header));
605 void QPAGenerator::writeGMap()
607 const quint16 glyphCount = fe->glyphCount();
609 writeUInt16(QFontEngineQPA::GMapBlock);
610 writeUInt16(0); // padding
611 writeUInt32(glyphCount * 4);
613 QByteArray &buffer = dev->buffer();
614 const int numBytes = glyphCount * sizeof(quint32);
615 qint64 pos = buffer.size();
616 buffer.resize(pos + numBytes);
617 qMemSet(buffer.data() + pos, 0xff, numBytes);
618 dev->seek(pos + numBytes);
621 void QPAGenerator::writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data)
624 writeUInt16(0); // padding
625 const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
626 writeUInt32(data.size() + padSize);
628 for (int i = 0; i < padSize; ++i)
632 void QPAGenerator::writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string)
635 writeUInt16(string.length());
639 void QPAGenerator::writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value)
642 writeUInt16(sizeof(value));
646 void QPAGenerator::writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value)
649 writeUInt16(sizeof(value));
653 void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value)
656 writeUInt16(sizeof(quint32));
657 writeUInt32(value.value());
662 Creates a new multi QPA engine.
664 This function takes ownership of the QFontEngine, increasing it's refcount.
666 QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks)
667 : QFontEngineMulti(fallbacks.size() + 1),
668 fallbackFamilies(fallbacks), script(_script)
672 fontDef = engines[0]->fontDef;
675 void QFontEngineMultiQPA::loadEngine(int at)
677 Q_ASSERT(at < engines.size());
678 Q_ASSERT(engines.at(at) == 0);
680 QFontDef request = fontDef;
681 request.styleStrategy |= QFont::NoFontMerging;
682 request.family = fallbackFamilies.at(at-1);
683 engines[at] = QFontDatabase::findFont(script,
686 Q_ASSERT(engines[at]);
687 engines[at]->ref.ref();
688 engines[at]->fontDef = request;