1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qfontengine_qpf_p.h"
44 #include "private/qpaintengine_raster_p.h"
45 #include <QtCore/qlibraryinfo.h>
46 #include <QtCore/qfileinfo.h>
48 #include <QtCore/qfile.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qbuffer.h>
51 #if !defined(QT_NO_FREETYPE)
52 #include "private/qfontengine_ft_p.h"
54 #include "private/qcore_unix_p.h" // overrides QT_OPEN
59 #include <sys/types.h>
67 #ifndef QT_NO_QWS_QPF2
69 #include "qpfutil.cpp"
71 QT_BEGIN_INCLUDE_NAMESPACE
73 #include "qplatformdefs.h"
74 QT_END_INCLUDE_NAMESPACE
76 //#define DEBUG_HEADER
77 //#define DEBUG_FONTENGINE
79 #if defined(DEBUG_HEADER)
80 # define DEBUG_VERIFY qDebug
82 # define DEBUG_VERIFY if (0) qDebug
85 #define READ_VERIFY(type, variable) \
86 if (tagPtr + sizeof(type) > endPtr) { \
87 DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \
90 variable = qFromBigEndian<type>(tagPtr); \
91 DEBUG_VERIFY() << "read value" << variable << "of type " #type; \
92 tagPtr += sizeof(type)
95 T readValue(const uchar *&data)
97 T value = qFromBigEndian<T>(data);
102 #define VERIFY(condition) \
103 if (!(condition)) { \
104 DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \
108 #define VERIFY_TAG(condition) \
109 if (!(condition)) { \
110 DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \
114 static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr)
117 READ_VERIFY(quint16, tag);
118 READ_VERIFY(quint16, length);
119 if (tag == QFontEngineQPF::Tag_EndOfHeader)
121 if (tag < QFontEngineQPF::NumTags) {
122 switch (tagTypes[tag]) {
123 case QFontEngineQPF::BitFieldType:
124 case QFontEngineQPF::StringType:
125 // can't do anything...
127 case QFontEngineQPF::UInt32Type:
128 VERIFY_TAG(length == sizeof(quint32));
130 case QFontEngineQPF::FixedType:
131 VERIFY_TAG(length == sizeof(quint32));
133 case QFontEngineQPF::UInt8Type:
134 VERIFY_TAG(length == sizeof(quint8));
137 #if defined(DEBUG_HEADER)
139 qDebug() << "tag data" << hex << *tagPtr;
140 else if (length == 4)
141 qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
144 return tagPtr + length;
147 const QFontEngineQPF::Glyph *QFontEngineQPF::findGlyph(glyph_t g) const
149 if (!g || g >= glyphMapEntries)
151 const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
152 quint32 glyphPos = qFromBigEndian<quint32>(gmapPtr[g]);
153 if (glyphPos > glyphDataSize) {
154 if (glyphPos == 0xffffffff)
156 #if defined(DEBUG_FONTENGINE)
157 qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
159 #if !defined(QT_NO_FREETYPE) && !defined(QT_FONTS_ARE_RESOURCES)
160 const_cast<QFontEngineQPF *>(this)->remapFontData();
162 if (glyphPos > glyphDataSize)
165 return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
168 bool QFontEngineQPF::verifyHeader(const uchar *data, int size)
170 VERIFY(size >= int(sizeof(Header)));
171 const Header *header = reinterpret_cast<const Header *>(data);
172 if (header->magic[0] != 'Q'
173 || header->magic[1] != 'P'
174 || header->magic[2] != 'F'
175 || header->magic[3] != '2')
178 VERIFY(header->majorVersion <= CurrentMajorVersion);
179 const quint16 dataSize = qFromBigEndian<quint16>(header->dataSize);
180 VERIFY(size >= int(sizeof(Header)) + dataSize);
182 const uchar *tagPtr = data + sizeof(Header);
183 const uchar *tagEndPtr = tagPtr + dataSize;
184 while (tagPtr < tagEndPtr - 3) {
185 tagPtr = verifyTag(tagPtr, tagEndPtr);
189 VERIFY(tagPtr <= tagEndPtr);
193 QVariant QFontEngineQPF::extractHeaderField(const uchar *data, HeaderTag requestedTag)
195 const Header *header = reinterpret_cast<const Header *>(data);
196 const uchar *tagPtr = data + sizeof(Header);
197 const uchar *endPtr = tagPtr + qFromBigEndian<quint16>(header->dataSize);
198 while (tagPtr < endPtr - 3) {
199 quint16 tag = readValue<quint16>(tagPtr);
200 quint16 length = readValue<quint16>(tagPtr);
201 if (tag == requestedTag) {
202 switch (tagTypes[requestedTag]) {
204 return QVariant(QString::fromUtf8(reinterpret_cast<const char *>(tagPtr), length));
206 return QVariant(readValue<quint32>(tagPtr));
208 return QVariant(uint(*tagPtr));
210 return QVariant(QFixed::fromFixed(readValue<quint32>(tagPtr)).toReal());
212 return QVariant(QByteArray(reinterpret_cast<const char *>(tagPtr), length));
215 } else if (tag == Tag_EndOfHeader) {
224 #endif // QT_NO_QWS_QPF2
226 QString qws_fontCacheDir()
229 dir = QDir::tempPath();
230 dir.append(QLatin1String("/fonts/"));
232 if (!qd.exists() && !qd.mkpath(dir))
233 dir = QDir::tempPath();
237 #ifndef QT_NO_QWS_QPF2
239 #ifndef QT_FONTS_ARE_RESOURCES
240 QList<QByteArray> QFontEngineQPF::cleanUpAfterClientCrash(const QList<int> &crashedClientIds)
242 QList<QByteArray> removedFonts;
243 QDir dir(qws_fontCacheDir(), QLatin1String("*.qsf"));
244 for (int i = 0; i < int(dir.count()); ++i) {
245 const QByteArray fileName = QFile::encodeName(dir.absoluteFilePath(dir[i]));
247 int fd = QT_OPEN(fileName.constData(), O_RDONLY, 0);
251 if (QT_FSTAT(fd, &st)) {
252 #if defined(DEBUG_FONTENGINE)
253 qDebug() << "stat failed! " << fileName;
256 nDataSize = st.st_size;
259 if (nDataSize >= (int)sizeof(QFontEngineQPF::Header)) {
260 void *header = ::mmap(0, sizeof(QFontEngineQPF::Header), PROT_READ, MAP_SHARED, fd, 0);
261 if (header && header != MAP_FAILED) {
262 quint32 lockValue = reinterpret_cast<QFontEngineQPF::Header *>(header)->lock;
264 if (lockValue && crashedClientIds.contains(lockValue)) {
265 removedFonts.append(fileName);
266 QFile::remove(QFile::decodeName(fileName));
269 ::munmap(header, sizeof(QFontEngineQPF::Header));
272 #if defined(DEBUG_FONTENGINE)
273 qDebug() << "Unsufficient header data in QSF file " << fileName;
279 if (!removedFonts.isEmpty())
280 qDebug() << "list of corrupted and removed fonts:" << removedFonts;
285 static inline unsigned int getChar(const QChar *str, int &i, const int len)
287 uint ucs4 = str[i].unicode();
288 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
290 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
294 #ifdef QT_FONTS_ARE_RESOURCES
295 QFontEngineQPF::QFontEngineQPF(const QFontDef &def, const uchar *bytes, int size)
296 : fd(-1), fontData(bytes), dataSize(size), renderingFontEngine(0)
298 QFontEngineQPF::QFontEngineQPF(const QFontDef &def, int fileDescriptor, QFontEngine *fontEngine)
299 : fd(fileDescriptor), fontData(0), dataSize(0), renderingFontEngine(fontEngine)
312 if (renderingFontEngine)
313 glyphFormat = renderingFontEngine->glyphFormat;
314 kerning_pairs_loaded = false;
317 #if defined(DEBUG_FONTENGINE)
318 qDebug() << "QFontEngineQPF::QFontEngineQPF( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
321 #ifndef QT_FONTS_ARE_RESOURCES
323 if (!renderingFontEngine)
326 fileName = fontDef.family.toLower() + QLatin1Char('_')
327 + QString::number(fontDef.pixelSize)
328 + QLatin1Char('_') + QString::number(fontDef.weight)
329 + (fontDef.style != QFont::StyleNormal ?
330 QLatin1String("_italic") : QLatin1String(""))
331 + QLatin1String(".qsf");
332 fileName.replace(QLatin1Char(' '), QLatin1Char('_'));
333 fileName.prepend(qws_fontCacheDir());
335 encodedFileName = QFile::encodeName(fileName);
336 if (::access(encodedFileName, F_OK) == 0) {
337 #if defined(DEBUG_FONTENGINE)
338 qDebug() << "found existing qpf:" << fileName;
340 if (::access(encodedFileName, W_OK | R_OK) == 0) {
341 fd = QT_OPEN(encodedFileName, O_RDWR);
343 // read-write access failed - try read-only access
344 if (fd == -1 && ::access(encodedFileName, R_OK) == 0) {
345 fd = QT_OPEN(encodedFileName, O_RDONLY);
347 #if defined(DEBUG_FONTENGINE)
348 qErrnoWarning("QFontEngineQPF: unable to open %s", encodedName.constData());
354 #if defined(DEBUG_FONTENGINE)
355 qWarning("QFontEngineQPF: insufficient access rights to %s", encodedName.constData());
360 #if defined(DEBUG_FONTENGINE)
361 qDebug() << "creating qpf on the fly:" << fileName;
363 if (::access(QFile::encodeName(qws_fontCacheDir()), W_OK) == 0) {
364 fd = QT_OPEN(encodedFileName, O_RDWR | O_EXCL | O_CREAT, 0644);
366 #if defined(DEBUG_FONTENGINE)
367 qErrnoWarning(errno, "QFontEngineQPF: open() failed for %s", encodedName.constData());
373 buffer.open(QIODevice::ReadWrite);
374 QPFGenerator generator(&buffer, renderingFontEngine);
375 generator.generate();
377 const QByteArray &data = buffer.data();
378 if (QT_WRITE(fd, data.constData(), data.size()) == -1) {
379 #if defined(DEBUG_FONTENGINE)
380 qErrnoWarning(errno, "QFontEngineQPF: write() failed for %s", encodedName.constData());
382 QFile::remove(fileName);
386 #if defined(DEBUG_FONTENGINE)
387 qErrnoWarning(errno, "QFontEngineQPF: access() failed for %s", qPrintable(qws_fontCacheDir()));
395 if (QT_FSTAT(fd, &st)) {
396 #if defined(DEBUG_FONTENGINE)
397 qErrnoWarning(errno, "QFontEngineQPF: fstat failed!");
401 dataSize = st.st_size;
404 fontData = (const uchar *)::mmap(0, st.st_size, PROT_READ | (renderingFontEngine ? PROT_WRITE : 0), MAP_SHARED, fd, 0);
405 if (!fontData || fontData == (const uchar *)MAP_FAILED) {
406 #if defined(DEBUG_FONTENGINE)
407 perror("mmap failed");
412 #endif //QT_FONTS_ARE_RESOURCES
414 if (!verifyHeader(fontData, dataSize)) {
415 #if defined(DEBUG_FONTENGINE)
416 qDebug() << "verifyHeader failed!";
421 const Header *header = reinterpret_cast<const Header *>(fontData);
423 readOnly = (header->lock == 0xffffffff);
425 const uchar *data = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize);
426 const uchar *endPtr = fontData + dataSize;
427 while (data <= endPtr - 8) {
428 quint16 blockTag = readValue<quint16>(data);
429 data += 2; // skip padding
430 quint32 blockSize = readValue<quint32>(data);
432 if (blockTag == CMapBlock) {
433 cmapOffset = data - fontData;
434 cmapSize = blockSize;
435 } else if (blockTag == GMapBlock) {
436 glyphMapOffset = data - fontData;
437 glyphMapEntries = blockSize / 4;
438 } else if (blockTag == GlyphBlock) {
439 glyphDataOffset = data - fontData;
440 glyphDataSize = blockSize;
446 face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
447 face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
448 #if !defined(QT_NO_FREETYPE) && !defined(QT_FONTS_ARE_RESOURCES)
449 freetype = QFreetypeFace::getFace(face_id);
452 #ifndef QT_NO_SETTINGS
453 QLibraryInfo::location(QLibraryInfo::LibrariesPath) +
455 QLatin1String("/fonts/") +
456 QFileInfo(QFile::decodeName(face_id.filename)).fileName();
457 face_id.filename = QFile::encodeName(newPath);
458 freetype = QFreetypeFace::getFace(face_id);
461 const quint32 qpfTtfRevision = extractHeaderField(fontData, Tag_FontRevision).toUInt();
464 bool ok = freetype->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd'), data, &length);
465 if (!ok || length != 4
466 || qFromBigEndian<quint32>(data) != qpfTtfRevision) {
467 freetype->release(face_id);
471 if (!cmapOffset && freetype) {
472 freetypeCMapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
473 externalCMap = reinterpret_cast<const uchar *>(freetypeCMapTable.constData());
474 cmapSize = freetypeCMapTable.size();
480 int tableSize = cmapSize;
481 const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
483 cmapOffset = cmapPtr - fontData;
486 } else if (externalCMap) {
487 int tableSize = cmapSize;
488 externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
491 // verify all the positions in the glyphMap
492 if (glyphMapOffset) {
493 const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
494 for (uint i = 0; i < glyphMapEntries; ++i) {
495 quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]);
496 if (glyphDataPos == 0xffffffff)
498 if (glyphDataPos >= glyphDataSize) {
507 #if defined(DEBUG_FONTENGINE)
509 qDebug() << "fontData" << fontData << "dataSize" << dataSize
510 << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
511 << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
512 << "fd" << fd << "glyphDataSize" << glyphDataSize;
516 QFontEngineQPF::~QFontEngineQPF()
518 delete renderingFontEngine;
520 if (munmap((void *)fontData, dataSize) == -1) {
521 #if defined(DEBUG_FONTENGINE)
522 qErrnoWarning(errno, "~QFontEngineQPF: Unable to munmap");
528 #if !defined(QT_NO_FREETYPE)
530 freetype->release(face_id);
534 bool QFontEngineQPF::getSfntTableData(uint tag, uchar *buffer, uint *length) const
536 #if !defined(QT_NO_FREETYPE)
538 return freetype->getSfntTable(tag, buffer, length);
546 bool QFontEngineQPF::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
548 if (!externalCMap && !cmapOffset && renderingFontEngine) {
549 if (!renderingFontEngine->stringToCMap(str, len, glyphs, nglyphs, flags))
551 #ifndef QT_NO_FREETYPE
552 const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(*glyphs);
557 if (*nglyphs < len) {
562 #if defined(DEBUG_FONTENGINE)
563 QSet<QChar> seenGlyphs;
566 const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
568 bool mirrored = flags & QTextEngine::RightToLeft;
571 for (int i = 0; i < len; ++i) {
572 unsigned int uc = getChar(str, i, len);
573 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
574 if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
575 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
579 for (int i = 0; i < len; ++i) {
580 unsigned int uc = getChar(str, i, len);
582 uc = QChar::mirroredChar(uc);
583 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
584 #if 0 && defined(DEBUG_FONTENGINE)
586 if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
587 qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
589 seenGlyphs.insert(c);
595 *nglyphs = glyph_pos;
596 glyphs->numGlyphs = glyph_pos;
597 recalcAdvances(glyphs, flags);
601 void QFontEngineQPF::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
603 #ifndef QT_NO_FREETYPE
604 const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(*glyphs);
606 for (int i = 0; i < glyphs->numGlyphs; ++i) {
607 const Glyph *g = findGlyph(glyphs->glyphs[i]);
609 glyphs->glyphs[i] = 0;
612 glyphs->advances_x[i] = g->advance;
613 glyphs->advances_y[i] = 0;
617 QImage QFontEngineQPF::alphaMapForGlyph(glyph_t g)
619 const Glyph *glyph = findGlyph(g);
623 const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
625 QImage image(glyph->width, glyph->height, QImage::Format_Indexed8);
626 for (int j=0; j<256; ++j)
627 image.setColor(j, qRgba(0, 0, 0, j));
629 for (int i=0; i<glyph->height; ++i) {
630 memcpy(image.scanLine(i), bits, glyph->bytesPerLine);
631 bits += glyph->bytesPerLine;
636 void QFontEngineQPF::draw(QPaintEngine *p, qreal _x, qreal _y, const QTextItemInt &si)
638 QPaintEngineState *pState = p->state;
639 QRasterPaintEngine *paintEngine = static_cast<QRasterPaintEngine*>(p);
641 QTransform matrix = pState->transform();
642 matrix.translate(_x, _y);
643 QFixed x = QFixed::fromReal(matrix.dx());
644 QFixed y = QFixed::fromReal(matrix.dy());
646 QVarLengthArray<QFixedPoint> positions;
647 QVarLengthArray<glyph_t> glyphs;
648 getGlyphPositions(si.glyphs, matrix, si.flags, glyphs, positions);
649 if (glyphs.size() == 0)
652 for(int i = 0; i < glyphs.size(); i++) {
653 const Glyph *glyph = findGlyph(glyphs[i]);
657 const int depth = 8; //###
659 paintEngine->alphaPenBlt(reinterpret_cast<const uchar *>(glyph) + sizeof(Glyph), glyph->bytesPerLine, depth,
660 qRound(positions[i].x) + glyph->x,
661 qRound(positions[i].y) + glyph->y,
662 glyph->width, glyph->height);
666 void QFontEngineQPF::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
668 if (renderingFontEngine &&
669 (renderingFontEngine->type() != QFontEngine::Proxy
670 || static_cast<QProxyFontEngine *>(renderingFontEngine)->capabilities() & QAbstractFontEngine::CanOutlineGlyphs)) {
671 renderingFontEngine->addOutlineToPath(x, y, glyphs, path, flags);
674 addBitmapFontToPath(x, y, glyphs, path, flags);
677 glyph_metrics_t QFontEngineQPF::boundingBox(const QGlyphLayout &glyphs)
679 #ifndef QT_NO_FREETYPE
680 const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(glyphs);
683 glyph_metrics_t overall;
684 // initialize with line height, we get the same behaviour on all platforms
685 overall.y = -ascent();
686 overall.height = ascent() + descent() + 1;
690 for (int i = 0; i < glyphs.numGlyphs; i++) {
691 const Glyph *g = findGlyph(glyphs.glyphs[i]);
695 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
696 QFixed y = overall.yoff + glyphs.offsets[i].y + g->y;
697 overall.x = qMin(overall.x, x);
698 overall.y = qMin(overall.y, y);
699 xmax = qMax(xmax, x + g->width);
700 ymax = qMax(ymax, y + g->height);
701 overall.xoff += g->advance;
703 overall.height = qMax(overall.height, ymax - overall.y);
704 overall.width = xmax - overall.x;
709 glyph_metrics_t QFontEngineQPF::boundingBox(glyph_t glyph)
711 #ifndef QT_NO_FREETYPE
713 QGlyphLayoutArray<1> tmp;
714 tmp.glyphs[0] = glyph;
715 const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(tmp);
718 glyph_metrics_t overall;
719 const Glyph *g = findGlyph(glyph);
724 overall.width = g->width;
725 overall.height = g->height;
726 overall.xoff = g->advance;
730 QFixed QFontEngineQPF::ascent() const
732 return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
735 QFixed QFontEngineQPF::descent() const
737 return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
740 QFixed QFontEngineQPF::leading() const
742 return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
745 qreal QFontEngineQPF::maxCharWidth() const
747 return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
750 qreal QFontEngineQPF::minLeftBearing() const
752 return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
755 qreal QFontEngineQPF::minRightBearing() const
757 return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
760 QFixed QFontEngineQPF::underlinePosition() const
762 return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
765 QFixed QFontEngineQPF::lineThickness() const
767 return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
770 QFontEngine::Type QFontEngineQPF::type() const
772 return QFontEngine::QPF2;
775 bool QFontEngineQPF::canRender(const QChar *string, int len)
777 const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
780 for (int i = 0; i < len; ++i) {
781 unsigned int uc = getChar(string, i, len);
782 glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
784 g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
789 for (int i = 0; i < len; ++i) {
790 unsigned int uc = getChar(string, i, len);
791 if (!getTrueTypeGlyphIndex(cmap, uc))
798 bool QFontEngineQPF::isValid() const
800 return fontData && dataSize && (cmapOffset || externalCMap || renderingFontEngine)
801 && glyphMapOffset && glyphDataOffset && (fd >= 0 || glyphDataSize > 0);
804 #if !defined(QT_NO_FREETYPE)
805 FT_Face QFontEngineQPF::lockFace() const
809 FT_Face face = freetype->face;
812 const int ysize = qRound(fontDef.pixelSize * qreal(64));
813 const int xsize = ysize;
815 if (freetype->xsize != xsize || freetype->ysize != ysize) {
816 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
817 freetype->xsize = xsize;
818 freetype->ysize = ysize;
820 FT_Matrix identityMatrix;
821 identityMatrix.xx = 0x10000;
822 identityMatrix.yy = 0x10000;
823 identityMatrix.xy = 0;
824 identityMatrix.yx = 0;
825 if (freetype->matrix.xx != identityMatrix.xx ||
826 freetype->matrix.yy != identityMatrix.yy ||
827 freetype->matrix.xy != identityMatrix.xy ||
828 freetype->matrix.yx != identityMatrix.yx) {
829 freetype->matrix = identityMatrix;
830 FT_Set_Transform(face, &freetype->matrix, 0);
835 void QFontEngineQPF::unlockFace() const
840 void QFontEngineQPF::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
842 if (!kerning_pairs_loaded) {
843 kerning_pairs_loaded = true;
846 if (freetype->face->size->metrics.x_ppem != 0) {
847 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
849 const_cast<QFontEngineQPF *>(this)->loadKerningPairs(scalingFactor);
855 QFontEngine::doKerning(g, flags);
858 HB_Error QFontEngineQPF::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
861 return HB_Err_Not_Covered;
863 HB_Error result = freetype->getPointInOutline(glyph, flags, point, xpos, ypos, nPoints);
868 QFixed QFontEngineQPF::emSquareSize() const
871 return QFontEngine::emSquareSize();
872 if (FT_IS_SCALABLE(freetype->face))
873 return freetype->face->units_per_EM;
875 return freetype->face->size->metrics.y_ppem;
878 void QFontEngineQPF::ensureGlyphsLoaded(const QGlyphLayout &glyphs)
883 for (int i = 0; i < glyphs.numGlyphs; ++i) {
884 if (!glyphs.glyphs[i])
886 const Glyph *g = findGlyph(glyphs.glyphs[i]);
893 g = findGlyph(glyphs.glyphs[i]);
897 loadGlyph(glyphs.glyphs[i]);
901 #if defined(DEBUG_FONTENGINE)
902 qDebug() << "Finished rendering glyphs\n";
907 void QFontEngineQPF::loadGlyph(glyph_t glyph)
909 quint32 glyphPos = ~0;
911 if (!renderingFontEngine)
913 QImage img = renderingFontEngine->alphaMapForGlyph(glyph);
914 if (img.format() != QImage::Format_Indexed8) {
915 bool mono = img.depth() == 1;
916 img = img.convertToFormat(QImage::Format_Indexed8);
918 //### we know that 1 is opaque and 0 is transparent
919 uchar *byte = img.bits();
920 int count = img.byteCount();
925 glyph_metrics_t metrics = renderingFontEngine->boundingBox(glyph);
926 renderingFontEngine->removeGlyphFromCache(glyph);
928 off_t oldSize = ::lseek(fd, 0, SEEK_END);
929 if (oldSize == (off_t)-1)
933 g.width = img.width();
934 g.height = img.height();
935 g.bytesPerLine = img.bytesPerLine();
936 g.x = qRound(metrics.x);
937 g.y = qRound(metrics.y);
938 g.advance = qRound(metrics.xoff);
940 QT_WRITE(fd, &g, sizeof(g));
941 QT_WRITE(fd, img.bits(), img.byteCount());
943 glyphPos = oldSize - glyphDataOffset;
944 #if 0 && defined(DEBUG_FONTENGINE)
945 qDebug() << "glyphPos for new glyph" << glyph << "is" << glyphPos << "oldSize" << oldSize << "glyphDataOffset" << glyphDataOffset;
948 quint32 *gmap = (quint32 *)(fontData + glyphMapOffset);
949 gmap[glyph] = qToBigEndian(glyphPos);
951 glyphDataSize = glyphPos + sizeof(g) + img.byteCount();
952 quint32 *blockSizePtr = (quint32 *)(fontData + glyphDataOffset - 4);
953 *blockSizePtr = qToBigEndian(glyphDataSize);
956 bool QFontEngineQPF::lockFile()
958 // #### this does not handle the case when the process holding the
959 // lock hangs for some reason
961 lock.l_type = F_WRLCK;
962 lock.l_whence = SEEK_SET;
964 lock.l_len = 0; // lock the whole file
965 while (fcntl(fd, F_SETLKW, &lock) != 0) {
968 perror("locking qpf");
971 Header *header = (Header *)fontData;
973 lock.l_type = F_UNLCK;
974 if (fcntl(fd, F_SETLK, &lock) != 0)
975 perror("unlocking possibly corrupt qpf");
982 void QFontEngineQPF::unlockFile()
984 ((Header *)fontData)->lock = 0;
987 lock.l_type = F_UNLCK;
988 lock.l_whence = SEEK_SET;
990 lock.l_len = 0; // lock the whole file
991 if (fcntl(fd, F_SETLK, &lock) != 0) {
992 perror("unlocking qpf");
998 void QFontEngineQPF::remapFontData()
1000 off_t newFileSize = ::lseek(fd, 0, SEEK_END);
1001 if (newFileSize == (off_t)-1) {
1002 #ifdef DEBUG_FONTENGINE
1003 perror("QFontEngineQPF::remapFontData: lseek failed");
1009 #ifndef QT_NO_MREMAP
1010 fontData = static_cast<uchar *>(::mremap(const_cast<uchar *>(fontData), dataSize, newFileSize, MREMAP_MAYMOVE));
1011 if (!fontData || fontData == (const uchar *)MAP_FAILED) {
1012 # if defined(DEBUG_FONTENGINE)
1013 perror("QFontEngineQPF::remapFontData(): mremap failed");
1019 #endif // QT_NO_MREMAP
1021 int status = ::munmap((void *)fontData, dataSize);
1023 qErrnoWarning(status, "QFontEngineQPF::remapFomrData: munmap failed!");
1025 fontData = (const uchar *)::mmap(0, newFileSize, PROT_READ | (renderingFontEngine ? PROT_WRITE : 0),
1027 if (!fontData || fontData == (const uchar *)MAP_FAILED) {
1028 # if defined(DEBUG_FONTENGINE)
1029 perror("mmap failed");
1036 dataSize = newFileSize;
1037 glyphDataSize = newFileSize - glyphDataOffset;
1038 #if defined(DEBUG_FONTENGINE)
1039 qDebug() << "remapped the font file to" << newFileSize << "bytes";
1043 #endif // QT_NO_FREETYPE
1045 void QPFGenerator::generate()
1049 writeBlock(QFontEngineQPF::GlyphBlock, QByteArray());
1051 dev->seek(4); // position of header.lock
1055 void QPFGenerator::writeHeader()
1057 QFontEngineQPF::Header header;
1059 header.magic[0] = 'Q';
1060 header.magic[1] = 'P';
1061 header.magic[2] = 'F';
1062 header.magic[3] = '2';
1064 header.majorVersion = QFontEngineQPF::CurrentMajorVersion;
1065 header.minorVersion = QFontEngineQPF::CurrentMinorVersion;
1066 header.dataSize = 0;
1067 dev->write((const char *)&header, sizeof(header));
1069 writeTaggedString(QFontEngineQPF::Tag_FontName, fe->fontDef.family.toUtf8());
1071 QFontEngine::FaceId face = fe->faceId();
1072 writeTaggedString(QFontEngineQPF::Tag_FileName, face.filename);
1073 writeTaggedUInt32(QFontEngineQPF::Tag_FileIndex, face.index);
1078 bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
1080 const quint32 revision = qFromBigEndian<quint32>(data);
1081 writeTaggedUInt32(QFontEngineQPF::Tag_FontRevision, revision);
1085 writeTaggedQFixed(QFontEngineQPF::Tag_Ascent, fe->ascent());
1086 writeTaggedQFixed(QFontEngineQPF::Tag_Descent, fe->descent());
1087 writeTaggedQFixed(QFontEngineQPF::Tag_Leading, fe->leading());
1088 writeTaggedQFixed(QFontEngineQPF::Tag_XHeight, fe->xHeight());
1089 writeTaggedQFixed(QFontEngineQPF::Tag_AverageCharWidth, fe->averageCharWidth());
1090 writeTaggedQFixed(QFontEngineQPF::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth()));
1091 writeTaggedQFixed(QFontEngineQPF::Tag_LineThickness, fe->lineThickness());
1092 writeTaggedQFixed(QFontEngineQPF::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing()));
1093 writeTaggedQFixed(QFontEngineQPF::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing()));
1094 writeTaggedQFixed(QFontEngineQPF::Tag_UnderlinePosition, fe->underlinePosition());
1095 writeTaggedUInt8(QFontEngineQPF::Tag_PixelSize, fe->fontDef.pixelSize);
1096 writeTaggedUInt8(QFontEngineQPF::Tag_Weight, fe->fontDef.weight);
1097 writeTaggedUInt8(QFontEngineQPF::Tag_Style, fe->fontDef.style);
1099 writeTaggedUInt8(QFontEngineQPF::Tag_GlyphFormat, QFontEngineQPF::AlphamapGlyphs);
1101 writeTaggedString(QFontEngineQPF::Tag_EndOfHeader, QByteArray());
1104 const quint64 size = dev->pos();
1105 header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
1107 dev->write((const char *)&header, sizeof(header));
1111 void QPFGenerator::writeGMap()
1113 const quint16 glyphCount = fe->glyphCount();
1115 writeUInt16(QFontEngineQPF::GMapBlock);
1116 writeUInt16(0); // padding
1117 writeUInt32(glyphCount * 4);
1119 QByteArray &buffer = dev->buffer();
1120 const int numBytes = glyphCount * sizeof(quint32);
1121 qint64 pos = buffer.size();
1122 buffer.resize(pos + numBytes);
1123 memset(buffer.data() + pos, 0xff, numBytes);
1124 dev->seek(pos + numBytes);
1127 void QPFGenerator::writeBlock(QFontEngineQPF::BlockTag tag, const QByteArray &data)
1130 writeUInt16(0); // padding
1131 const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
1132 writeUInt32(data.size() + padSize);
1134 for (int i = 0; i < padSize; ++i)
1138 void QPFGenerator::writeTaggedString(QFontEngineQPF::HeaderTag tag, const QByteArray &string)
1141 writeUInt16(string.length());
1145 void QPFGenerator::writeTaggedUInt32(QFontEngineQPF::HeaderTag tag, quint32 value)
1148 writeUInt16(sizeof(value));
1152 void QPFGenerator::writeTaggedUInt8(QFontEngineQPF::HeaderTag tag, quint8 value)
1155 writeUInt16(sizeof(value));
1159 void QPFGenerator::writeTaggedQFixed(QFontEngineQPF::HeaderTag tag, QFixed value)
1162 writeUInt16(sizeof(quint32));
1163 writeUInt32(value.value());
1166 #endif // QT_NO_QWS_QPF2
1169 Creates a new multi qws engine.
1171 This function takes ownership of the QFontEngine, increasing it's refcount.
1173 QFontEngineMultiQWS::QFontEngineMultiQWS(QFontEngine *fe, int _script, const QStringList &fallbacks)
1174 : QFontEngineMulti(fallbacks.size() + 1),
1175 fallbackFamilies(fallbacks), script(_script)
1179 fontDef = engines[0]->fontDef;
1182 void QFontEngineMultiQWS::loadEngine(int at)
1184 Q_ASSERT(at < engines.size());
1185 Q_ASSERT(engines.at(at) == 0);
1187 QFontDef request = fontDef;
1188 request.styleStrategy |= QFont::NoFontMerging;
1189 request.family = fallbackFamilies.at(at-1);
1190 engines[at] = QFontDatabase::findFont(script,
1193 Q_ASSERT(engines[at]);
1194 engines[at]->ref.ref();
1195 engines[at]->fontDef = request;
1198 void QFontEngineMultiQWS::draw(QPaintEngine */*p*/, qreal /*x*/, qreal /*y*/, const QTextItemInt &/*si*/)
1200 qFatal("QFontEngineMultiQWS::draw should never be called!");