Get started with patching up the Qt GUI docs
[profile/ivi/qtbase.git] / src / gui / text / qfontengine_qpf.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qfontengine_qpf_p.h"
43
44 #include "private/qpaintengine_raster_p.h"
45 #include <QtCore/qlibraryinfo.h>
46 #include <QtCore/qfileinfo.h>
47
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"
53 #endif
54 #include "private/qcore_unix_p.h" // overrides QT_OPEN
55
56 // for mmap
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <sys/mman.h>
62 #include <fcntl.h>
63 #include <errno.h>
64
65 QT_BEGIN_NAMESPACE
66
67 #ifndef QT_NO_QWS_QPF2
68
69 #include "qpfutil.cpp"
70
71 QT_BEGIN_INCLUDE_NAMESPACE
72
73 #include "qplatformdefs.h"
74 QT_END_INCLUDE_NAMESPACE
75
76 //#define DEBUG_HEADER
77 //#define DEBUG_FONTENGINE
78
79 #if defined(DEBUG_HEADER)
80 # define DEBUG_VERIFY qDebug
81 #else
82 # define DEBUG_VERIFY if (0) qDebug
83 #endif
84
85 #define READ_VERIFY(type, variable) \
86     if (tagPtr + sizeof(type) > endPtr) { \
87         DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \
88         return 0; \
89     } \
90     variable = qFromBigEndian<type>(tagPtr); \
91     DEBUG_VERIFY() << "read value" << variable << "of type " #type; \
92     tagPtr += sizeof(type)
93
94 template <typename T>
95 T readValue(const uchar *&data)
96 {
97     T value = qFromBigEndian<T>(data);
98     data += sizeof(T);
99     return value;
100 }
101
102 #define VERIFY(condition) \
103     if (!(condition)) { \
104         DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \
105         return 0; \
106     }
107
108 #define VERIFY_TAG(condition) \
109     if (!(condition)) { \
110         DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \
111         return 0; \
112     }
113
114 static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr)
115 {
116     quint16 tag, length;
117     READ_VERIFY(quint16, tag);
118     READ_VERIFY(quint16, length);
119     if (tag == QFontEngineQPF::Tag_EndOfHeader)
120         return endPtr;
121     if (tag < QFontEngineQPF::NumTags) {
122         switch (tagTypes[tag]) {
123             case QFontEngineQPF::BitFieldType:
124             case QFontEngineQPF::StringType:
125                 // can't do anything...
126                 break;
127             case QFontEngineQPF::UInt32Type:
128                 VERIFY_TAG(length == sizeof(quint32));
129                 break;
130             case QFontEngineQPF::FixedType:
131                 VERIFY_TAG(length == sizeof(quint32));
132                 break;
133             case QFontEngineQPF::UInt8Type:
134                 VERIFY_TAG(length == sizeof(quint8));
135                 break;
136         }
137 #if defined(DEBUG_HEADER)
138         if (length == 1)
139             qDebug() << "tag data" << hex << *tagPtr;
140         else if (length == 4)
141             qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
142 #endif
143     }
144     return tagPtr + length;
145 }
146
147 const QFontEngineQPF::Glyph *QFontEngineQPF::findGlyph(glyph_t g) const
148 {
149     if (!g || g >= glyphMapEntries)
150         return 0;
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)
155             return 0;
156 #if defined(DEBUG_FONTENGINE)
157         qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
158 #endif
159 #if !defined(QT_NO_FREETYPE) && !defined(QT_FONTS_ARE_RESOURCES)
160         const_cast<QFontEngineQPF *>(this)->remapFontData();
161 #endif
162         if (glyphPos > glyphDataSize)
163             return 0;
164     }
165     return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
166 }
167
168 bool QFontEngineQPF::verifyHeader(const uchar *data, int size)
169 {
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')
176         return false;
177
178     VERIFY(header->majorVersion <= CurrentMajorVersion);
179     const quint16 dataSize = qFromBigEndian<quint16>(header->dataSize);
180     VERIFY(size >= int(sizeof(Header)) + dataSize);
181
182     const uchar *tagPtr = data + sizeof(Header);
183     const uchar *tagEndPtr = tagPtr + dataSize;
184     while (tagPtr < tagEndPtr - 3) {
185         tagPtr = verifyTag(tagPtr, tagEndPtr);
186         VERIFY(tagPtr);
187     }
188
189     VERIFY(tagPtr <= tagEndPtr);
190     return true;
191 }
192
193 QVariant QFontEngineQPF::extractHeaderField(const uchar *data, HeaderTag requestedTag)
194 {
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]) {
203                 case StringType:
204                     return QVariant(QString::fromUtf8(reinterpret_cast<const char *>(tagPtr), length));
205                 case UInt32Type:
206                     return QVariant(readValue<quint32>(tagPtr));
207                 case UInt8Type:
208                     return QVariant(uint(*tagPtr));
209                 case FixedType:
210                     return QVariant(QFixed::fromFixed(readValue<quint32>(tagPtr)).toReal());
211                 case BitFieldType:
212                     return QVariant(QByteArray(reinterpret_cast<const char *>(tagPtr), length));
213             }
214             return QVariant();
215         } else if (tag == Tag_EndOfHeader) {
216             break;
217         }
218         tagPtr += length;
219     }
220
221     return QVariant();
222 }
223
224 #endif // QT_NO_QWS_QPF2
225
226 QString qws_fontCacheDir()
227 {
228     QString dir;
229     dir = QDir::tempPath();
230     dir.append(QLatin1String("/fonts/"));
231     QDir qd(dir);
232     if (!qd.exists() && !qd.mkpath(dir))
233         dir = QDir::tempPath();
234     return dir;
235 }
236
237 #ifndef QT_NO_QWS_QPF2
238
239 #ifndef QT_FONTS_ARE_RESOURCES
240 QList<QByteArray> QFontEngineQPF::cleanUpAfterClientCrash(const QList<int> &crashedClientIds)
241 {
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]));
246
247         int fd = QT_OPEN(fileName.constData(), O_RDONLY, 0);
248         if (fd >= 0) {
249             QT_STATBUF st;
250             int nDataSize = 0;
251             if (QT_FSTAT(fd, &st)) {
252 #if defined(DEBUG_FONTENGINE)
253                 qDebug() << "stat failed! " << fileName;
254 #endif
255             } else {
256                 nDataSize = st.st_size;
257             }
258
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;
263
264                     if (lockValue && crashedClientIds.contains(lockValue)) {
265                         removedFonts.append(fileName);
266                         QFile::remove(QFile::decodeName(fileName));
267                     }
268
269                     ::munmap(header, sizeof(QFontEngineQPF::Header));
270                 }
271             } else {
272 #if defined(DEBUG_FONTENGINE)
273                 qDebug() << "Unsufficient header data in QSF file " << fileName;
274 #endif
275             }
276             QT_CLOSE(fd);
277         }
278     }
279     if (!removedFonts.isEmpty())
280         qDebug() << "list of corrupted and removed fonts:" << removedFonts;
281     return removedFonts;
282 }
283 #endif
284
285 static inline unsigned int getChar(const QChar *str, int &i, const int len)
286 {
287     uint ucs4 = str[i].unicode();
288     if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
289         ++i;
290         ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
291     }
292     return ucs4;
293 }
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)
297 #else
298 QFontEngineQPF::QFontEngineQPF(const QFontDef &def, int fileDescriptor, QFontEngine *fontEngine)
299     : fd(fileDescriptor), fontData(0), dataSize(0), renderingFontEngine(fontEngine)
300 #endif
301 {
302     fontDef = def;
303     cache_cost = 100;
304     freetype = 0;
305     externalCMap = 0;
306     cmapOffset = 0;
307     cmapSize = 0;
308     glyphMapOffset = 0;
309     glyphMapEntries = 0;
310     glyphDataOffset = 0;
311     glyphDataSize = 0;
312     if (renderingFontEngine)
313         glyphFormat = renderingFontEngine->glyphFormat;
314     kerning_pairs_loaded = false;
315     readOnly = true;
316
317 #if defined(DEBUG_FONTENGINE)
318     qDebug() << "QFontEngineQPF::QFontEngineQPF( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
319 #endif
320
321 #ifndef QT_FONTS_ARE_RESOURCES
322     if (fd < 0) {
323         if (!renderingFontEngine)
324             return;
325
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());
334
335         encodedFileName = QFile::encodeName(fileName);
336         if (::access(encodedFileName, F_OK) == 0) {
337 #if defined(DEBUG_FONTENGINE)
338             qDebug() << "found existing qpf:" << fileName;
339 #endif
340             if (::access(encodedFileName, W_OK | R_OK) == 0) {
341                 fd = QT_OPEN(encodedFileName, O_RDWR);
342             }
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);
346                 if (fd == -1) {
347 #if defined(DEBUG_FONTENGINE)
348                     qErrnoWarning("QFontEngineQPF: unable to open %s", encodedName.constData());
349 #endif
350                     return;
351                 }
352             }
353             if (fd == -1) {
354 #if defined(DEBUG_FONTENGINE)
355                 qWarning("QFontEngineQPF: insufficient access rights to %s", encodedName.constData());
356 #endif
357                 return;
358             }
359         } else {
360 #if defined(DEBUG_FONTENGINE)
361             qDebug() << "creating qpf on the fly:" << fileName;
362 #endif
363             if (::access(QFile::encodeName(qws_fontCacheDir()), W_OK) == 0) {
364                 fd = QT_OPEN(encodedFileName, O_RDWR | O_EXCL | O_CREAT, 0644);
365                 if (fd == -1) {
366 #if defined(DEBUG_FONTENGINE)
367                     qErrnoWarning(errno, "QFontEngineQPF: open() failed for %s", encodedName.constData());
368 #endif
369                     return;
370                 }
371
372                 QBuffer buffer;
373                 buffer.open(QIODevice::ReadWrite);
374                 QPFGenerator generator(&buffer, renderingFontEngine);
375                 generator.generate();
376                 buffer.close();
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());
381 #endif
382                     QFile::remove(fileName);
383                     return;
384                 }
385             } else {
386 #if defined(DEBUG_FONTENGINE)
387                 qErrnoWarning(errno, "QFontEngineQPF: access() failed for %s", qPrintable(qws_fontCacheDir()));
388 #endif
389                 return;
390             }
391         }
392     }
393
394     QT_STATBUF st;
395     if (QT_FSTAT(fd, &st)) {
396 #if defined(DEBUG_FONTENGINE)
397         qErrnoWarning(errno, "QFontEngineQPF: fstat failed!");
398 #endif
399         return;
400     }
401     dataSize = st.st_size;
402
403
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");
408 #endif
409         fontData = 0;
410         return;
411     }
412 #endif //QT_FONTS_ARE_RESOURCES
413
414     if (!verifyHeader(fontData, dataSize)) {
415 #if defined(DEBUG_FONTENGINE)
416         qDebug() << "verifyHeader failed!";
417 #endif
418         return;
419     }
420
421     const Header *header = reinterpret_cast<const Header *>(fontData);
422
423     readOnly = (header->lock == 0xffffffff);
424
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);
431
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;
441         }
442
443         data += blockSize;
444     }
445
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);
450     if (!freetype) {
451         QString newPath =
452 #ifndef QT_NO_SETTINGS
453             QLibraryInfo::location(QLibraryInfo::LibrariesPath) +
454 #endif
455                           QLatin1String("/fonts/") +
456                           QFileInfo(QFile::decodeName(face_id.filename)).fileName();
457         face_id.filename = QFile::encodeName(newPath);
458         freetype = QFreetypeFace::getFace(face_id);
459     }
460     if (freetype) {
461         const quint32 qpfTtfRevision = extractHeaderField(fontData, Tag_FontRevision).toUInt();
462         uchar data[4];
463         uint length = 4;
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);
468             freetype = 0;
469         }
470     }
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();
475     }
476 #endif
477
478     // get the real cmap
479     if (cmapOffset) {
480         int tableSize = cmapSize;
481         const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
482         if (cmapPtr)
483             cmapOffset = cmapPtr - fontData;
484         else
485             cmapOffset = 0;
486     } else if (externalCMap) {
487         int tableSize = cmapSize;
488         externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
489     }
490
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)
497                 continue;
498             if (glyphDataPos >= glyphDataSize) {
499                 // error
500                 glyphMapOffset = 0;
501                 glyphMapEntries = 0;
502                 break;
503             }
504         }
505     }
506
507 #if defined(DEBUG_FONTENGINE)
508     if (!isValid())
509         qDebug() << "fontData" <<  fontData << "dataSize" << dataSize
510                  << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
511                  << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
512                  << "fd" << fd << "glyphDataSize" << glyphDataSize;
513 #endif
514 }
515
516 QFontEngineQPF::~QFontEngineQPF()
517 {
518     delete renderingFontEngine;
519     if (fontData) {
520         if (munmap((void *)fontData, dataSize) == -1) {
521 #if defined(DEBUG_FONTENGINE)
522             qErrnoWarning(errno, "~QFontEngineQPF: Unable to munmap");
523 #endif
524         }
525     }
526     if (fd != -1)
527         ::close(fd);
528 #if !defined(QT_NO_FREETYPE)
529     if (freetype)
530         freetype->release(face_id);
531 #endif
532 }
533
534 bool QFontEngineQPF::getSfntTableData(uint tag, uchar *buffer, uint *length) const
535 {
536 #if !defined(QT_NO_FREETYPE)
537     if (freetype)
538         return freetype->getSfntTable(tag, buffer, length);
539 #endif
540     Q_UNUSED(tag);
541     Q_UNUSED(buffer);
542     *length = 0;
543     return false;
544 }
545
546 bool QFontEngineQPF::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
547 {
548     if (!externalCMap && !cmapOffset && renderingFontEngine) {
549         if (!renderingFontEngine->stringToCMap(str, len, glyphs, nglyphs, flags))
550             return false;
551 #ifndef QT_NO_FREETYPE
552         const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(*glyphs);
553 #endif
554         return true;
555     }
556
557     if (*nglyphs < len) {
558         *nglyphs = len;
559         return false;
560     }
561
562 #if defined(DEBUG_FONTENGINE)
563     QSet<QChar> seenGlyphs;
564 #endif
565
566     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
567
568     bool mirrored = flags & QTextEngine::RightToLeft;
569     int glyph_pos = 0;
570     if (symbol) {
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);
576             ++glyph_pos;
577         }
578     } else {
579         for (int i = 0; i < len; ++i) {
580             unsigned int uc = getChar(str, i, len);
581             if (mirrored)
582                 uc = QChar::mirroredChar(uc);
583             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
584 #if 0 && defined(DEBUG_FONTENGINE)
585             QChar c(uc);
586             if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
587                 qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
588
589             seenGlyphs.insert(c);
590 #endif
591             ++glyph_pos;
592         }
593     }
594
595     *nglyphs = glyph_pos;
596     glyphs->numGlyphs = glyph_pos;
597     recalcAdvances(glyphs, flags);
598     return true;
599 }
600
601 void QFontEngineQPF::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
602 {
603 #ifndef QT_NO_FREETYPE
604     const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(*glyphs);
605 #endif
606     for (int i = 0; i < glyphs->numGlyphs; ++i) {
607         const Glyph *g = findGlyph(glyphs->glyphs[i]);
608         if (!g) {
609             glyphs->glyphs[i] = 0;
610             continue;
611         }
612         glyphs->advances_x[i] = g->advance;
613         glyphs->advances_y[i] = 0;
614     }
615 }
616
617 QImage QFontEngineQPF::alphaMapForGlyph(glyph_t g)
618 {
619     const Glyph *glyph = findGlyph(g);
620     if (!glyph)
621         return QImage();
622
623     const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
624
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));
628
629     for (int i=0; i<glyph->height; ++i) {
630         memcpy(image.scanLine(i), bits, glyph->bytesPerLine);
631         bits += glyph->bytesPerLine;
632     }
633     return image;
634 }
635
636 void QFontEngineQPF::draw(QPaintEngine *p, qreal _x, qreal _y, const QTextItemInt &si)
637 {
638     QPaintEngineState *pState = p->state;
639     QRasterPaintEngine *paintEngine = static_cast<QRasterPaintEngine*>(p);
640
641     QTransform matrix = pState->transform();
642     matrix.translate(_x, _y);
643     QFixed x = QFixed::fromReal(matrix.dx());
644     QFixed y = QFixed::fromReal(matrix.dy());
645
646     QVarLengthArray<QFixedPoint> positions;
647     QVarLengthArray<glyph_t> glyphs;
648     getGlyphPositions(si.glyphs, matrix, si.flags, glyphs, positions);
649     if (glyphs.size() == 0)
650         return;
651
652     for(int i = 0; i < glyphs.size(); i++) {
653         const Glyph *glyph = findGlyph(glyphs[i]);
654         if (!glyph)
655             continue;
656
657         const int depth = 8; //###
658
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);
663     }
664 }
665
666 void QFontEngineQPF::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
667 {
668     if (renderingFontEngine &&
669         (renderingFontEngine->type() != QFontEngine::Proxy
670          || static_cast<QProxyFontEngine *>(renderingFontEngine)->capabilities() & QAbstractFontEngine::CanOutlineGlyphs)) {
671         renderingFontEngine->addOutlineToPath(x, y, glyphs, path, flags);
672         return;
673     }
674     addBitmapFontToPath(x, y, glyphs, path, flags);
675 }
676
677 glyph_metrics_t QFontEngineQPF::boundingBox(const QGlyphLayout &glyphs)
678 {
679 #ifndef QT_NO_FREETYPE
680     const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(glyphs);
681 #endif
682
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;
687
688     QFixed ymax = 0;
689     QFixed xmax = 0;
690     for (int i = 0; i < glyphs.numGlyphs; i++) {
691         const Glyph *g = findGlyph(glyphs.glyphs[i]);
692         if (!g)
693             continue;
694
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;
702     }
703     overall.height = qMax(overall.height, ymax - overall.y);
704     overall.width = xmax - overall.x;
705
706     return overall;
707 }
708
709 glyph_metrics_t QFontEngineQPF::boundingBox(glyph_t glyph)
710 {
711 #ifndef QT_NO_FREETYPE
712     {
713         QGlyphLayoutArray<1> tmp;
714         tmp.glyphs[0] = glyph;
715         const_cast<QFontEngineQPF *>(this)->ensureGlyphsLoaded(tmp);
716     }
717 #endif
718     glyph_metrics_t overall;
719     const Glyph *g = findGlyph(glyph);
720     if (!g)
721         return overall;
722     overall.x = g->x;
723     overall.y = g->y;
724     overall.width = g->width;
725     overall.height = g->height;
726     overall.xoff = g->advance;
727     return overall;
728 }
729
730 QFixed QFontEngineQPF::ascent() const
731 {
732     return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
733 }
734
735 QFixed QFontEngineQPF::descent() const
736 {
737     return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
738 }
739
740 QFixed QFontEngineQPF::leading() const
741 {
742     return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
743 }
744
745 qreal QFontEngineQPF::maxCharWidth() const
746 {
747     return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
748 }
749
750 qreal QFontEngineQPF::minLeftBearing() const
751 {
752     return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
753 }
754
755 qreal QFontEngineQPF::minRightBearing() const
756 {
757     return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
758 }
759
760 QFixed QFontEngineQPF::underlinePosition() const
761 {
762     return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
763 }
764
765 QFixed QFontEngineQPF::lineThickness() const
766 {
767     return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
768 }
769
770 QFontEngine::Type QFontEngineQPF::type() const
771 {
772     return QFontEngine::QPF2;
773 }
774
775 bool QFontEngineQPF::canRender(const QChar *string, int len)
776 {
777     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
778
779     if (symbol) {
780         for (int i = 0; i < len; ++i) {
781             unsigned int uc = getChar(string, i, len);
782             glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
783             if(!g && uc < 0x100)
784                 g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
785             if (!g)
786                 return false;
787         }
788     } else {
789         for (int i = 0; i < len; ++i) {
790             unsigned int uc = getChar(string, i, len);
791             if (!getTrueTypeGlyphIndex(cmap, uc))
792                 return false;
793         }
794     }
795     return true;
796 }
797
798 bool QFontEngineQPF::isValid() const
799 {
800     return fontData && dataSize && (cmapOffset || externalCMap || renderingFontEngine)
801            && glyphMapOffset && glyphDataOffset && (fd >= 0 || glyphDataSize > 0);
802 }
803
804 #if !defined(QT_NO_FREETYPE)
805 FT_Face QFontEngineQPF::lockFace() const
806 {
807     Q_ASSERT(freetype);
808     freetype->lock();
809     FT_Face face = freetype->face;
810
811     // ### not perfect
812     const int ysize = qRound(fontDef.pixelSize * qreal(64));
813     const int xsize = ysize;
814
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;
819     }
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);
831     }
832     return face;
833 }
834
835 void QFontEngineQPF::unlockFace() const
836 {
837     freetype->unlock();
838 }
839
840 void QFontEngineQPF::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
841 {
842     if (!kerning_pairs_loaded) {
843         kerning_pairs_loaded = true;
844         if (freetype) {
845             lockFace();
846             if (freetype->face->size->metrics.x_ppem != 0) {
847                 QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
848                 unlockFace();
849                 const_cast<QFontEngineQPF *>(this)->loadKerningPairs(scalingFactor);
850             } else {
851                 unlockFace();
852             }
853         }
854     }
855     QFontEngine::doKerning(g, flags);
856 }
857
858 HB_Error QFontEngineQPF::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
859 {
860     if (!freetype)
861         return HB_Err_Not_Covered;
862     lockFace();
863     HB_Error result = freetype->getPointInOutline(glyph, flags, point, xpos, ypos, nPoints);
864     unlockFace();
865     return result;
866 }
867
868 QFixed QFontEngineQPF::emSquareSize() const
869 {
870     if (!freetype)
871         return QFontEngine::emSquareSize();
872     if (FT_IS_SCALABLE(freetype->face))
873         return freetype->face->units_per_EM;
874     else
875         return freetype->face->size->metrics.y_ppem;
876 }
877
878 void QFontEngineQPF::ensureGlyphsLoaded(const QGlyphLayout &glyphs)
879 {
880     if (readOnly)
881         return;
882     bool locked = false;
883     for (int i = 0; i < glyphs.numGlyphs; ++i) {
884         if (!glyphs.glyphs[i])
885             continue;
886         const Glyph *g = findGlyph(glyphs.glyphs[i]);
887         if (g)
888             continue;
889         if (!locked) {
890             if (!lockFile())
891                 return;
892             locked = true;
893             g = findGlyph(glyphs.glyphs[i]);
894             if (g)
895                 continue;
896         }
897         loadGlyph(glyphs.glyphs[i]);
898     }
899     if (locked) {
900         unlockFile();
901 #if defined(DEBUG_FONTENGINE)
902         qDebug() << "Finished rendering glyphs\n";
903 #endif
904     }
905 }
906
907 void QFontEngineQPF::loadGlyph(glyph_t glyph)
908 {
909     quint32 glyphPos = ~0;
910
911     if (!renderingFontEngine)
912         return;
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);
917         if (mono) {
918             //### we know that 1 is opaque and 0 is transparent
919             uchar *byte = img.bits();
920             int count = img.byteCount();
921             while (count--)
922                 *byte++ *= 0xff;
923         }
924     }
925     glyph_metrics_t metrics = renderingFontEngine->boundingBox(glyph);
926     renderingFontEngine->removeGlyphFromCache(glyph);
927
928     off_t oldSize = ::lseek(fd, 0, SEEK_END);
929     if (oldSize == (off_t)-1)
930         return;
931
932     Glyph g;
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);
939
940     QT_WRITE(fd, &g, sizeof(g));
941     QT_WRITE(fd, img.bits(), img.byteCount());
942
943     glyphPos = oldSize - glyphDataOffset;
944 #if 0 && defined(DEBUG_FONTENGINE)
945     qDebug() << "glyphPos for new glyph" << glyph << "is" << glyphPos << "oldSize" << oldSize << "glyphDataOffset" << glyphDataOffset;
946 #endif
947
948     quint32 *gmap = (quint32 *)(fontData + glyphMapOffset);
949     gmap[glyph] = qToBigEndian(glyphPos);
950
951     glyphDataSize = glyphPos + sizeof(g) + img.byteCount();
952     quint32 *blockSizePtr = (quint32 *)(fontData + glyphDataOffset - 4);
953     *blockSizePtr = qToBigEndian(glyphDataSize);
954 }
955
956 bool QFontEngineQPF::lockFile()
957 {
958     // #### this does not handle the case when the process holding the
959     // lock hangs for some reason
960     struct flock lock;
961     lock.l_type = F_WRLCK;
962     lock.l_whence = SEEK_SET;
963     lock.l_start = 0;
964     lock.l_len = 0; // lock the whole file
965     while (fcntl(fd, F_SETLKW, &lock) != 0) {
966         if (errno == EINTR)
967             continue;
968         perror("locking qpf");
969         return false;
970     }
971     Header *header = (Header *)fontData;
972     if (header->lock) {
973         lock.l_type = F_UNLCK;
974         if (fcntl(fd, F_SETLK, &lock) != 0)
975             perror("unlocking possibly corrupt qpf");
976         return false;
977     }
978     header->lock = 1;
979     return true;
980 }
981
982 void QFontEngineQPF::unlockFile()
983 {
984     ((Header *)fontData)->lock = 0;
985
986     struct flock lock;
987     lock.l_type = F_UNLCK;
988     lock.l_whence = SEEK_SET;
989     lock.l_start = 0;
990     lock.l_len = 0; // lock the whole file
991     if (fcntl(fd, F_SETLK, &lock) != 0) {
992         perror("unlocking qpf");
993     }
994
995     remapFontData();
996 }
997
998 void QFontEngineQPF::remapFontData()
999 {
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");
1004 #endif
1005         fontData = 0;
1006         return;
1007     }
1008
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");
1014 #  endif
1015         fontData = 0;
1016     }
1017
1018     if (!fontData)
1019 #endif // QT_NO_MREMAP
1020     {
1021         int status = ::munmap((void *)fontData, dataSize);
1022         if (status != 0)
1023             qErrnoWarning(status, "QFontEngineQPF::remapFomrData: munmap failed!");
1024
1025         fontData = (const uchar *)::mmap(0, newFileSize, PROT_READ | (renderingFontEngine ? PROT_WRITE : 0),
1026                                          MAP_SHARED, fd, 0);
1027         if (!fontData || fontData == (const uchar *)MAP_FAILED) {
1028 #  if defined(DEBUG_FONTENGINE)
1029             perror("mmap failed");
1030 #  endif
1031             fontData = 0;
1032             return;
1033         }
1034     }
1035
1036     dataSize = newFileSize;
1037     glyphDataSize = newFileSize - glyphDataOffset;
1038 #if defined(DEBUG_FONTENGINE)
1039     qDebug() << "remapped the font file to" << newFileSize << "bytes";
1040 #endif
1041 }
1042
1043 #endif // QT_NO_FREETYPE
1044
1045 void QPFGenerator::generate()
1046 {
1047     writeHeader();
1048     writeGMap();
1049     writeBlock(QFontEngineQPF::GlyphBlock, QByteArray());
1050
1051     dev->seek(4); // position of header.lock
1052     writeUInt32(0);
1053 }
1054
1055 void QPFGenerator::writeHeader()
1056 {
1057     QFontEngineQPF::Header header;
1058
1059     header.magic[0] = 'Q';
1060     header.magic[1] = 'P';
1061     header.magic[2] = 'F';
1062     header.magic[3] = '2';
1063     header.lock = 1;
1064     header.majorVersion = QFontEngineQPF::CurrentMajorVersion;
1065     header.minorVersion = QFontEngineQPF::CurrentMinorVersion;
1066     header.dataSize = 0;
1067     dev->write((const char *)&header, sizeof(header));
1068
1069     writeTaggedString(QFontEngineQPF::Tag_FontName, fe->fontDef.family.toUtf8());
1070
1071     QFontEngine::FaceId face = fe->faceId();
1072     writeTaggedString(QFontEngineQPF::Tag_FileName, face.filename);
1073     writeTaggedUInt32(QFontEngineQPF::Tag_FileIndex, face.index);
1074
1075     {
1076         uchar data[4];
1077         uint len = 4;
1078         bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
1079         if (ok) {
1080             const quint32 revision = qFromBigEndian<quint32>(data);
1081             writeTaggedUInt32(QFontEngineQPF::Tag_FontRevision, revision);
1082         }
1083     }
1084
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);
1098
1099     writeTaggedUInt8(QFontEngineQPF::Tag_GlyphFormat, QFontEngineQPF::AlphamapGlyphs);
1100
1101     writeTaggedString(QFontEngineQPF::Tag_EndOfHeader, QByteArray());
1102     align4();
1103
1104     const quint64 size = dev->pos();
1105     header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
1106     dev->seek(0);
1107     dev->write((const char *)&header, sizeof(header));
1108     dev->seek(size);
1109 }
1110
1111 void QPFGenerator::writeGMap()
1112 {
1113     const quint16 glyphCount = fe->glyphCount();
1114
1115     writeUInt16(QFontEngineQPF::GMapBlock);
1116     writeUInt16(0); // padding
1117     writeUInt32(glyphCount * 4);
1118
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);
1125 }
1126
1127 void QPFGenerator::writeBlock(QFontEngineQPF::BlockTag tag, const QByteArray &data)
1128 {
1129     writeUInt16(tag);
1130     writeUInt16(0); // padding
1131     const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
1132     writeUInt32(data.size() + padSize);
1133     dev->write(data);
1134     for (int i = 0; i < padSize; ++i)
1135         writeUInt8(0);
1136 }
1137
1138 void QPFGenerator::writeTaggedString(QFontEngineQPF::HeaderTag tag, const QByteArray &string)
1139 {
1140     writeUInt16(tag);
1141     writeUInt16(string.length());
1142     dev->write(string);
1143 }
1144
1145 void QPFGenerator::writeTaggedUInt32(QFontEngineQPF::HeaderTag tag, quint32 value)
1146 {
1147     writeUInt16(tag);
1148     writeUInt16(sizeof(value));
1149     writeUInt32(value);
1150 }
1151
1152 void QPFGenerator::writeTaggedUInt8(QFontEngineQPF::HeaderTag tag, quint8 value)
1153 {
1154     writeUInt16(tag);
1155     writeUInt16(sizeof(value));
1156     writeUInt8(value);
1157 }
1158
1159 void QPFGenerator::writeTaggedQFixed(QFontEngineQPF::HeaderTag tag, QFixed value)
1160 {
1161     writeUInt16(tag);
1162     writeUInt16(sizeof(quint32));
1163     writeUInt32(value.value());
1164 }
1165
1166 #endif // QT_NO_QWS_QPF2
1167
1168 /*
1169     Creates a new multi qws engine.
1170
1171     This function takes ownership of the QFontEngine, increasing it's refcount.
1172 */
1173 QFontEngineMultiQWS::QFontEngineMultiQWS(QFontEngine *fe, int _script, const QStringList &fallbacks)
1174     : QFontEngineMulti(fallbacks.size() + 1),
1175       fallbackFamilies(fallbacks), script(_script)
1176 {
1177     engines[0] = fe;
1178     fe->ref.ref();
1179     fontDef = engines[0]->fontDef;
1180 }
1181
1182 void QFontEngineMultiQWS::loadEngine(int at)
1183 {
1184     Q_ASSERT(at < engines.size());
1185     Q_ASSERT(engines.at(at) == 0);
1186
1187     QFontDef request = fontDef;
1188     request.styleStrategy |= QFont::NoFontMerging;
1189     request.family = fallbackFamilies.at(at-1);
1190     engines[at] = QFontDatabase::findFont(script,
1191                                           /*fontprivate*/0,
1192                                           request);
1193     Q_ASSERT(engines[at]);
1194     engines[at]->ref.ref();
1195     engines[at]->fontDef = request;
1196 }
1197
1198 void QFontEngineMultiQWS::draw(QPaintEngine */*p*/, qreal /*x*/, qreal /*y*/, const QTextItemInt &/*si*/)
1199 {
1200     qFatal("QFontEngineMultiQWS::draw should never be called!");
1201 }
1202
1203 QT_END_NAMESPACE