Fix uses of qRound on non-floating-point types.
[profile/ivi/qtbase.git] / src / gui / text / qfontengine_qpa.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qfontengine_qpa_p.h"
43
44 #include <QtCore/QFile>
45 #include <QtCore/QFileInfo>
46 #include <QtCore/QDir>
47 #include <QtCore/QBuffer>
48
49 #include <QtGui/private/qapplication_p.h>
50 #include <QtGui/QPlatformFontDatabase>
51 #include <QtGui/private/qpaintengine_raster_p.h>
52
53 QT_BEGIN_NAMESPACE
54
55 //#define DEBUG_HEADER
56 //#define DEBUG_FONTENGINE
57
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
80 };
81
82
83 #if defined(DEBUG_HEADER)
84 # define DEBUG_VERIFY qDebug
85 #else
86 # define DEBUG_VERIFY if (0) qDebug
87 #endif
88
89 #define READ_VERIFY(type, variable) \
90     if (tagPtr + sizeof(type) > endPtr) { \
91         DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \
92         return 0; \
93     } \
94     variable = qFromBigEndian<type>(tagPtr); \
95     DEBUG_VERIFY() << "read value" << variable << "of type " #type; \
96     tagPtr += sizeof(type)
97
98 template <typename T>
99 T readValue(const uchar *&data)
100 {
101     T value = qFromBigEndian<T>(data);
102     data += sizeof(T);
103     return value;
104 }
105
106 #define VERIFY(condition) \
107     if (!(condition)) { \
108         DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \
109         return 0; \
110     }
111
112 #define VERIFY_TAG(condition) \
113     if (!(condition)) { \
114         DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \
115         return 0; \
116     }
117
118 static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr)
119 {
120     quint16 tag, length;
121     READ_VERIFY(quint16, tag);
122     READ_VERIFY(quint16, length);
123     if (tag == QFontEngineQPA::Tag_EndOfHeader)
124         return endPtr;
125     if (tag < QFontEngineQPA::NumTags) {
126         switch (tagTypes[tag]) {
127             case QFontEngineQPA::BitFieldType:
128             case QFontEngineQPA::StringType:
129                 // can't do anything...
130                 break;
131             case QFontEngineQPA::UInt32Type:
132                 VERIFY_TAG(length == sizeof(quint32));
133                 break;
134             case QFontEngineQPA::FixedType:
135                 VERIFY_TAG(length == sizeof(quint32));
136                 break;
137             case QFontEngineQPA::UInt8Type:
138                 VERIFY_TAG(length == sizeof(quint8));
139                 break;
140         }
141 #if defined(DEBUG_HEADER)
142         if (length == 1)
143             qDebug() << "tag data" << hex << *tagPtr;
144         else if (length == 4)
145             qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
146 #endif
147     }
148     return tagPtr + length;
149 }
150
151 const QFontEngineQPA::Glyph *QFontEngineQPA::findGlyph(glyph_t g) const
152 {
153     if (!g || g >= glyphMapEntries)
154         return 0;
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)
159             return 0;
160 #if defined(DEBUG_FONTENGINE)
161         qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
162 #endif
163         if (glyphPos > glyphDataSize)
164             return 0;
165     }
166     return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
167 }
168
169 bool QFontEngineQPA::verifyHeader(const uchar *data, int size)
170 {
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')
177         return false;
178
179     VERIFY(header->majorVersion <= CurrentMajorVersion);
180     const quint16 dataSize = qFromBigEndian<quint16>(header->dataSize);
181     VERIFY(size >= int(sizeof(Header)) + dataSize);
182
183     const uchar *tagPtr = data + sizeof(Header);
184     const uchar *tagEndPtr = tagPtr + dataSize;
185     while (tagPtr < tagEndPtr - 3) {
186         tagPtr = verifyTag(tagPtr, tagEndPtr);
187         VERIFY(tagPtr);
188     }
189
190     VERIFY(tagPtr <= tagEndPtr);
191     return true;
192 }
193
194 QVariant QFontEngineQPA::extractHeaderField(const uchar *data, HeaderTag requestedTag)
195 {
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]) {
204                 case StringType:
205                     return QVariant(QString::fromUtf8(reinterpret_cast<const char *>(tagPtr), length));
206                 case UInt32Type:
207                     return QVariant(readValue<quint32>(tagPtr));
208                 case UInt8Type:
209                     return QVariant(uint(*tagPtr));
210                 case FixedType:
211                     return QVariant(QFixed::fromFixed(readValue<quint32>(tagPtr)).toReal());
212                 case BitFieldType:
213                     return QVariant(QByteArray(reinterpret_cast<const char *>(tagPtr), length));
214             }
215             return QVariant();
216         } else if (tag == Tag_EndOfHeader) {
217             break;
218         }
219         tagPtr += length;
220     }
221
222     return QVariant();
223 }
224
225
226
227 static inline unsigned int getChar(const QChar *str, int &i, const int len)
228 {
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;
234             ++i;
235         }
236     }
237     return uc;
238 }
239
240 QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
241     : fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
242 {
243     fontDef = def;
244     cache_cost = 100;
245     externalCMap = 0;
246     cmapOffset = 0;
247     cmapSize = 0;
248     glyphMapOffset = 0;
249     glyphMapEntries = 0;
250     glyphDataOffset = 0;
251     glyphDataSize = 0;
252     kerning_pairs_loaded = false;
253     readOnly = true;
254
255 #if defined(DEBUG_FONTENGINE)
256     qDebug() << "QFontEngineQPA::QFontEngineQPA( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
257 #endif
258
259     if (!verifyHeader(fontData, dataSize)) {
260 #if defined(DEBUG_FONTENGINE)
261         qDebug() << "verifyHeader failed!";
262 #endif
263         return;
264     }
265
266     const Header *header = reinterpret_cast<const Header *>(fontData);
267
268     readOnly = (header->lock == 0xffffffff);
269
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);
276
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;
286         }
287
288         imgData += blockSize;
289     }
290
291     face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
292     face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
293
294     // get the real cmap
295     if (cmapOffset) {
296         int tableSize = cmapSize;
297         const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
298         if (cmapPtr)
299             cmapOffset = cmapPtr - fontData;
300         else
301             cmapOffset = 0;
302     } else if (externalCMap) {
303         int tableSize = cmapSize;
304         externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
305     }
306
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)
313                 continue;
314             if (glyphDataPos >= glyphDataSize) {
315                 // error
316                 glyphMapOffset = 0;
317                 glyphMapEntries = 0;
318                 break;
319             }
320         }
321     }
322
323 #if defined(DEBUG_FONTENGINE)
324     if (!isValid())
325         qDebug() << "fontData" <<  fontData << "dataSize" << dataSize
326                  << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
327                  << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
328                  << "fd" << fd << "glyphDataSize" << glyphDataSize;
329 #endif
330 }
331
332 QFontEngineQPA::~QFontEngineQPA()
333 {
334 }
335
336 bool QFontEngineQPA::getSfntTableData(uint tag, uchar *buffer, uint *length) const
337 {
338     Q_UNUSED(tag);
339     Q_UNUSED(buffer);
340     *length = 0;
341     return false;
342 }
343
344 bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
345 {
346     if (*nglyphs < len) {
347         *nglyphs = len;
348         return false;
349     }
350
351 #if defined(DEBUG_FONTENGINE)
352     QSet<QChar> seenGlyphs;
353 #endif
354
355     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
356
357     bool mirrored = flags & QTextEngine::RightToLeft;
358     int glyph_pos = 0;
359     if (symbol) {
360         for (int i = 0; i < len; ++i) {
361             unsigned int uc = getChar(str, i, len);
362             if (mirrored)
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);
367             ++glyph_pos;
368         }
369     } else {
370         for (int i = 0; i < len; ++i) {
371             unsigned int uc = getChar(str, i, len);
372             if (mirrored)
373                 uc = QChar::mirroredChar(uc);
374             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
375 #if 0 && defined(DEBUG_FONTENGINE)
376             QChar c(uc);
377             if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
378                 qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
379
380             seenGlyphs.insert(c);
381 #endif
382             ++glyph_pos;
383         }
384     }
385
386     *nglyphs = glyph_pos;
387     glyphs->numGlyphs = glyph_pos;
388     recalcAdvances(glyphs, flags);
389     return true;
390 }
391
392 void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
393 {
394     for (int i = 0; i < glyphs->numGlyphs; ++i) {
395         const Glyph *g = findGlyph(glyphs->glyphs[i]);
396         if (!g) {
397             glyphs->glyphs[i] = 0;
398             continue;
399         }
400         glyphs->advances_x[i] = g->advance;
401         glyphs->advances_y[i] = 0;
402     }
403 }
404
405 QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g)
406 {
407     const Glyph *glyph = findGlyph(g);
408     if (!glyph)
409         return QImage();
410
411     const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
412
413     QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8);
414
415     return image;
416 }
417
418 void QFontEngineQPA::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
419 {
420     addBitmapFontToPath(x, y, glyphs, path, flags);
421 }
422
423 glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs)
424 {
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;
429
430     QFixed ymax = 0;
431     QFixed xmax = 0;
432     for (int i = 0; i < glyphs.numGlyphs; i++) {
433         const Glyph *g = findGlyph(glyphs.glyphs[i]);
434         if (!g)
435             continue;
436
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;
444     }
445     overall.height = qMax(overall.height, ymax - overall.y);
446     overall.width = xmax - overall.x;
447
448     return overall;
449 }
450
451 glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph)
452 {
453     glyph_metrics_t overall;
454     const Glyph *g = findGlyph(glyph);
455     if (!g)
456         return overall;
457     overall.x = g->x;
458     overall.y = g->y;
459     overall.width = g->width;
460     overall.height = g->height;
461     overall.xoff = g->advance;
462     return overall;
463 }
464
465 QFixed QFontEngineQPA::ascent() const
466 {
467     return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
468 }
469
470 QFixed QFontEngineQPA::descent() const
471 {
472     return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
473 }
474
475 QFixed QFontEngineQPA::leading() const
476 {
477     return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
478 }
479
480 qreal QFontEngineQPA::maxCharWidth() const
481 {
482     return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
483 }
484
485 qreal QFontEngineQPA::minLeftBearing() const
486 {
487     return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
488 }
489
490 qreal QFontEngineQPA::minRightBearing() const
491 {
492     return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
493 }
494
495 QFixed QFontEngineQPA::underlinePosition() const
496 {
497     return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
498 }
499
500 QFixed QFontEngineQPA::lineThickness() const
501 {
502     return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
503 }
504
505 QFontEngine::Type QFontEngineQPA::type() const
506 {
507     return QFontEngine::QPF2;
508 }
509
510 bool QFontEngineQPA::canRender(const QChar *string, int len)
511 {
512     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
513
514     if (symbol) {
515         for (int i = 0; i < len; ++i) {
516             unsigned int uc = getChar(string, i, len);
517             glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
518             if(!g && uc < 0x100)
519                 g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
520             if (!g)
521                 return false;
522         }
523     } else {
524         for (int i = 0; i < len; ++i) {
525             unsigned int uc = getChar(string, i, len);
526             if (!getTrueTypeGlyphIndex(cmap, uc))
527                 return false;
528         }
529     }
530     return true;
531 }
532
533 bool QFontEngineQPA::isValid() const
534 {
535     return fontData && dataSize && (cmapOffset || externalCMap)
536            && glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
537 }
538
539 void QPAGenerator::generate()
540 {
541     writeHeader();
542     writeGMap();
543     writeBlock(QFontEngineQPA::GlyphBlock, QByteArray());
544
545     dev->seek(4); // position of header.lock
546     writeUInt32(0);
547 }
548
549 void QPAGenerator::writeHeader()
550 {
551     QFontEngineQPA::Header header;
552
553     header.magic[0] = 'Q';
554     header.magic[1] = 'P';
555     header.magic[2] = 'F';
556     header.magic[3] = '2';
557     header.lock = 1;
558     header.majorVersion = QFontEngineQPA::CurrentMajorVersion;
559     header.minorVersion = QFontEngineQPA::CurrentMinorVersion;
560     header.dataSize = 0;
561     dev->write((const char *)&header, sizeof(header));
562
563     writeTaggedString(QFontEngineQPA::Tag_FontName, fe->fontDef.family.toUtf8());
564
565     QFontEngine::FaceId face = fe->faceId();
566     writeTaggedString(QFontEngineQPA::Tag_FileName, face.filename);
567     writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index);
568
569     {
570         uchar data[4];
571         uint len = 4;
572         bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
573         if (ok) {
574             const quint32 revision = qFromBigEndian<quint32>(data);
575             writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision);
576         }
577     }
578
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);
592
593     writeTaggedUInt8(QFontEngineQPA::Tag_GlyphFormat, QFontEngineQPA::AlphamapGlyphs);
594
595     writeTaggedString(QFontEngineQPA::Tag_EndOfHeader, QByteArray());
596     align4();
597
598     const quint64 size = dev->pos();
599     header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
600     dev->seek(0);
601     dev->write((const char *)&header, sizeof(header));
602     dev->seek(size);
603 }
604
605 void QPAGenerator::writeGMap()
606 {
607     const quint16 glyphCount = fe->glyphCount();
608
609     writeUInt16(QFontEngineQPA::GMapBlock);
610     writeUInt16(0); // padding
611     writeUInt32(glyphCount * 4);
612
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);
619 }
620
621 void QPAGenerator::writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data)
622 {
623     writeUInt16(tag);
624     writeUInt16(0); // padding
625     const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
626     writeUInt32(data.size() + padSize);
627     dev->write(data);
628     for (int i = 0; i < padSize; ++i)
629         writeUInt8(0);
630 }
631
632 void QPAGenerator::writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string)
633 {
634     writeUInt16(tag);
635     writeUInt16(string.length());
636     dev->write(string);
637 }
638
639 void QPAGenerator::writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value)
640 {
641     writeUInt16(tag);
642     writeUInt16(sizeof(value));
643     writeUInt32(value);
644 }
645
646 void QPAGenerator::writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value)
647 {
648     writeUInt16(tag);
649     writeUInt16(sizeof(value));
650     writeUInt8(value);
651 }
652
653 void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value)
654 {
655     writeUInt16(tag);
656     writeUInt16(sizeof(quint32));
657     writeUInt32(value.value());
658 }
659
660
661 /*
662     Creates a new multi QPA engine.
663
664     This function takes ownership of the QFontEngine, increasing it's refcount.
665 */
666 QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks)
667     : QFontEngineMulti(fallbacks.size() + 1),
668       fallbackFamilies(fallbacks), script(_script)
669 {
670     engines[0] = fe;
671     fe->ref.ref();
672     fontDef = engines[0]->fontDef;
673 }
674
675 void QFontEngineMultiQPA::loadEngine(int at)
676 {
677     Q_ASSERT(at < engines.size());
678     Q_ASSERT(engines.at(at) == 0);
679
680     QFontDef request = fontDef;
681     request.styleStrategy |= QFont::NoFontMerging;
682     request.family = fallbackFamilies.at(at-1);
683     engines[at] = QFontDatabase::findFont(script,
684                                           /*fontprivate*/0,
685                                           request);
686     Q_ASSERT(engines[at]);
687     engines[at]->ref.ref();
688     engines[at]->fontDef = request;
689 }
690
691 QT_END_NAMESPACE