Export QTextImageHandler and add accessor for image
[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/QPlatformFontDatabase>
50 #include <QtGui/private/qpaintengine_raster_p.h>
51
52 QT_BEGIN_NAMESPACE
53
54 //#define DEBUG_HEADER
55 //#define DEBUG_FONTENGINE
56
57 static QFontEngineQPA::TagType tagTypes[QFontEngineQPA::NumTags] = {
58     QFontEngineQPA::StringType, // FontName
59     QFontEngineQPA::StringType, // FileName
60     QFontEngineQPA::UInt32Type, // FileIndex
61     QFontEngineQPA::UInt32Type, // FontRevision
62     QFontEngineQPA::StringType, // FreeText
63     QFontEngineQPA::FixedType,  // Ascent
64     QFontEngineQPA::FixedType,  // Descent
65     QFontEngineQPA::FixedType,  // Leading
66     QFontEngineQPA::FixedType,  // XHeight
67     QFontEngineQPA::FixedType,  // AverageCharWidth
68     QFontEngineQPA::FixedType,  // MaxCharWidth
69     QFontEngineQPA::FixedType,  // LineThickness
70     QFontEngineQPA::FixedType,  // MinLeftBearing
71     QFontEngineQPA::FixedType,  // MinRightBearing
72     QFontEngineQPA::FixedType,  // UnderlinePosition
73     QFontEngineQPA::UInt8Type,  // GlyphFormat
74     QFontEngineQPA::UInt8Type,  // PixelSize
75     QFontEngineQPA::UInt8Type,  // Weight
76     QFontEngineQPA::UInt8Type,  // Style
77     QFontEngineQPA::StringType, // EndOfHeader
78     QFontEngineQPA::BitFieldType// WritingSystems
79 };
80
81
82 #if defined(DEBUG_HEADER)
83 # define DEBUG_VERIFY qDebug
84 #else
85 # define DEBUG_VERIFY if (0) qDebug
86 #endif
87
88 #define READ_VERIFY(type, variable) \
89     if (tagPtr + sizeof(type) > endPtr) { \
90         DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \
91         return 0; \
92     } \
93     variable = qFromBigEndian<type>(tagPtr); \
94     DEBUG_VERIFY() << "read value" << variable << "of type " #type; \
95     tagPtr += sizeof(type)
96
97 template <typename T>
98 T readValue(const uchar *&data)
99 {
100     T value = qFromBigEndian<T>(data);
101     data += sizeof(T);
102     return value;
103 }
104
105 #define VERIFY(condition) \
106     if (!(condition)) { \
107         DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \
108         return 0; \
109     }
110
111 #define VERIFY_TAG(condition) \
112     if (!(condition)) { \
113         DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \
114         return 0; \
115     }
116
117 static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr)
118 {
119     quint16 tag, length;
120     READ_VERIFY(quint16, tag);
121     READ_VERIFY(quint16, length);
122     if (tag == QFontEngineQPA::Tag_EndOfHeader)
123         return endPtr;
124     if (tag < QFontEngineQPA::NumTags) {
125         switch (tagTypes[tag]) {
126             case QFontEngineQPA::BitFieldType:
127             case QFontEngineQPA::StringType:
128                 // can't do anything...
129                 break;
130             case QFontEngineQPA::UInt32Type:
131                 VERIFY_TAG(length == sizeof(quint32));
132                 break;
133             case QFontEngineQPA::FixedType:
134                 VERIFY_TAG(length == sizeof(quint32));
135                 break;
136             case QFontEngineQPA::UInt8Type:
137                 VERIFY_TAG(length == sizeof(quint8));
138                 break;
139         }
140 #if defined(DEBUG_HEADER)
141         if (length == 1)
142             qDebug() << "tag data" << hex << *tagPtr;
143         else if (length == 4)
144             qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
145 #endif
146     }
147     return tagPtr + length;
148 }
149
150 const QFontEngineQPA::Glyph *QFontEngineQPA::findGlyph(glyph_t g) const
151 {
152     if (!g || g >= glyphMapEntries)
153         return 0;
154     const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
155     quint32 glyphPos = qFromBigEndian<quint32>(gmapPtr[g]);
156     if (glyphPos > glyphDataSize) {
157         if (glyphPos == 0xffffffff)
158             return 0;
159 #if defined(DEBUG_FONTENGINE)
160         qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
161 #endif
162         if (glyphPos > glyphDataSize)
163             return 0;
164     }
165     return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
166 }
167
168 bool QFontEngineQPA::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 QFontEngineQPA::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
225
226 static inline unsigned int getChar(const QChar *str, int &i, const int len)
227 {
228     uint ucs4 = str[i].unicode();
229     if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
230         ++i;
231         ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
232     }
233     return ucs4;
234 }
235
236 QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
237     : fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
238 {
239     fontDef = def;
240     cache_cost = 100;
241     externalCMap = 0;
242     cmapOffset = 0;
243     cmapSize = 0;
244     glyphMapOffset = 0;
245     glyphMapEntries = 0;
246     glyphDataOffset = 0;
247     glyphDataSize = 0;
248     kerning_pairs_loaded = false;
249     readOnly = true;
250
251 #if defined(DEBUG_FONTENGINE)
252     qDebug() << "QFontEngineQPA::QFontEngineQPA( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
253 #endif
254
255     if (!verifyHeader(fontData, dataSize)) {
256 #if defined(DEBUG_FONTENGINE)
257         qDebug() << "verifyHeader failed!";
258 #endif
259         return;
260     }
261
262     const Header *header = reinterpret_cast<const Header *>(fontData);
263
264     readOnly = (header->lock == 0xffffffff);
265
266     const uchar *imgData = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize);
267     const uchar *endPtr = fontData + dataSize;
268     while (imgData <= endPtr - 8) {
269         quint16 blockTag = readValue<quint16>(imgData);
270         imgData += 2; // skip padding
271         quint32 blockSize = readValue<quint32>(imgData);
272
273         if (blockTag == CMapBlock) {
274             cmapOffset = imgData - fontData;
275             cmapSize = blockSize;
276         } else if (blockTag == GMapBlock) {
277             glyphMapOffset = imgData - fontData;
278             glyphMapEntries = blockSize / 4;
279         } else if (blockTag == GlyphBlock) {
280             glyphDataOffset = imgData - fontData;
281             glyphDataSize = blockSize;
282         }
283
284         imgData += blockSize;
285     }
286
287     face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
288     face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
289
290     // get the real cmap
291     if (cmapOffset) {
292         int tableSize = cmapSize;
293         const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
294         if (cmapPtr)
295             cmapOffset = cmapPtr - fontData;
296         else
297             cmapOffset = 0;
298     } else if (externalCMap) {
299         int tableSize = cmapSize;
300         externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
301     }
302
303     // verify all the positions in the glyphMap
304     if (glyphMapOffset) {
305         const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
306         for (uint i = 0; i < glyphMapEntries; ++i) {
307             quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]);
308             if (glyphDataPos == 0xffffffff)
309                 continue;
310             if (glyphDataPos >= glyphDataSize) {
311                 // error
312                 glyphMapOffset = 0;
313                 glyphMapEntries = 0;
314                 break;
315             }
316         }
317     }
318
319 #if defined(DEBUG_FONTENGINE)
320     if (!isValid())
321         qDebug() << "fontData" <<  fontData << "dataSize" << dataSize
322                  << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
323                  << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
324                  << "fd" << fd << "glyphDataSize" << glyphDataSize;
325 #endif
326 }
327
328 QFontEngineQPA::~QFontEngineQPA()
329 {
330 }
331
332 bool QFontEngineQPA::getSfntTableData(uint tag, uchar *buffer, uint *length) const
333 {
334     Q_UNUSED(tag);
335     Q_UNUSED(buffer);
336     *length = 0;
337     return false;
338 }
339
340 bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
341 {
342     if (*nglyphs < len) {
343         *nglyphs = len;
344         return false;
345     }
346
347 #if defined(DEBUG_FONTENGINE)
348     QSet<QChar> seenGlyphs;
349 #endif
350
351     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
352
353     bool mirrored = flags & QTextEngine::RightToLeft;
354     int glyph_pos = 0;
355     if (symbol) {
356         for (int i = 0; i < len; ++i) {
357             unsigned int uc = getChar(str, i, len);
358             if (mirrored)
359                 uc = QChar::mirroredChar(uc);
360             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
361             if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
362                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
363             ++glyph_pos;
364         }
365     } else {
366         for (int i = 0; i < len; ++i) {
367             unsigned int uc = getChar(str, i, len);
368             if (mirrored)
369                 uc = QChar::mirroredChar(uc);
370             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
371 #if 0 && defined(DEBUG_FONTENGINE)
372             QChar c(uc);
373             if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
374                 qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
375
376             seenGlyphs.insert(c);
377 #endif
378             ++glyph_pos;
379         }
380     }
381
382     *nglyphs = glyph_pos;
383     glyphs->numGlyphs = glyph_pos;
384     recalcAdvances(glyphs, flags);
385     return true;
386 }
387
388 void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
389 {
390     for (int i = 0; i < glyphs->numGlyphs; ++i) {
391         const Glyph *g = findGlyph(glyphs->glyphs[i]);
392         if (!g) {
393             glyphs->glyphs[i] = 0;
394             continue;
395         }
396         glyphs->advances_x[i] = g->advance;
397         glyphs->advances_y[i] = 0;
398     }
399 }
400
401 QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g)
402 {
403     const Glyph *glyph = findGlyph(g);
404     if (!glyph)
405         return QImage();
406
407     const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
408
409     QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8);
410
411     return image;
412 }
413
414 void QFontEngineQPA::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
415 {
416     addBitmapFontToPath(x, y, glyphs, path, flags);
417 }
418
419 glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs)
420 {
421     glyph_metrics_t overall;
422     // initialize with line height, we get the same behaviour on all platforms
423     overall.y = -ascent();
424     overall.height = ascent() + descent() + 1;
425
426     QFixed ymax = 0;
427     QFixed xmax = 0;
428     for (int i = 0; i < glyphs.numGlyphs; i++) {
429         const Glyph *g = findGlyph(glyphs.glyphs[i]);
430         if (!g)
431             continue;
432
433         QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
434         QFixed y = overall.yoff + glyphs.offsets[i].y + g->y;
435         overall.x = qMin(overall.x, x);
436         overall.y = qMin(overall.y, y);
437         xmax = qMax(xmax, x + g->width);
438         ymax = qMax(ymax, y + g->height);
439         overall.xoff += g->advance;
440     }
441     overall.height = qMax(overall.height, ymax - overall.y);
442     overall.width = xmax - overall.x;
443
444     return overall;
445 }
446
447 glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph)
448 {
449     glyph_metrics_t overall;
450     const Glyph *g = findGlyph(glyph);
451     if (!g)
452         return overall;
453     overall.x = g->x;
454     overall.y = g->y;
455     overall.width = g->width;
456     overall.height = g->height;
457     overall.xoff = g->advance;
458     return overall;
459 }
460
461 QFixed QFontEngineQPA::ascent() const
462 {
463     return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
464 }
465
466 QFixed QFontEngineQPA::descent() const
467 {
468     return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
469 }
470
471 QFixed QFontEngineQPA::leading() const
472 {
473     return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
474 }
475
476 qreal QFontEngineQPA::maxCharWidth() const
477 {
478     return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
479 }
480
481 qreal QFontEngineQPA::minLeftBearing() const
482 {
483     return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
484 }
485
486 qreal QFontEngineQPA::minRightBearing() const
487 {
488     return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
489 }
490
491 QFixed QFontEngineQPA::underlinePosition() const
492 {
493     return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
494 }
495
496 QFixed QFontEngineQPA::lineThickness() const
497 {
498     return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
499 }
500
501 QFontEngine::Type QFontEngineQPA::type() const
502 {
503     return QFontEngine::QPF2;
504 }
505
506 bool QFontEngineQPA::canRender(const QChar *string, int len)
507 {
508     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
509
510     if (symbol) {
511         for (int i = 0; i < len; ++i) {
512             unsigned int uc = getChar(string, i, len);
513             glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
514             if(!g && uc < 0x100)
515                 g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
516             if (!g)
517                 return false;
518         }
519     } else {
520         for (int i = 0; i < len; ++i) {
521             unsigned int uc = getChar(string, i, len);
522             if (!getTrueTypeGlyphIndex(cmap, uc))
523                 return false;
524         }
525     }
526     return true;
527 }
528
529 bool QFontEngineQPA::isValid() const
530 {
531     return fontData && dataSize && (cmapOffset || externalCMap)
532            && glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
533 }
534
535 void QPAGenerator::generate()
536 {
537     writeHeader();
538     writeGMap();
539     writeBlock(QFontEngineQPA::GlyphBlock, QByteArray());
540
541     dev->seek(4); // position of header.lock
542     writeUInt32(0);
543 }
544
545 void QPAGenerator::writeHeader()
546 {
547     QFontEngineQPA::Header header;
548
549     header.magic[0] = 'Q';
550     header.magic[1] = 'P';
551     header.magic[2] = 'F';
552     header.magic[3] = '2';
553     header.lock = 1;
554     header.majorVersion = QFontEngineQPA::CurrentMajorVersion;
555     header.minorVersion = QFontEngineQPA::CurrentMinorVersion;
556     header.dataSize = 0;
557     dev->write((const char *)&header, sizeof(header));
558
559     writeTaggedString(QFontEngineQPA::Tag_FontName, fe->fontDef.family.toUtf8());
560
561     QFontEngine::FaceId face = fe->faceId();
562     writeTaggedString(QFontEngineQPA::Tag_FileName, face.filename);
563     writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index);
564
565     {
566         uchar data[4];
567         uint len = 4;
568         bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
569         if (ok) {
570             const quint32 revision = qFromBigEndian<quint32>(data);
571             writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision);
572         }
573     }
574
575     writeTaggedQFixed(QFontEngineQPA::Tag_Ascent, fe->ascent());
576     writeTaggedQFixed(QFontEngineQPA::Tag_Descent, fe->descent());
577     writeTaggedQFixed(QFontEngineQPA::Tag_Leading, fe->leading());
578     writeTaggedQFixed(QFontEngineQPA::Tag_XHeight, fe->xHeight());
579     writeTaggedQFixed(QFontEngineQPA::Tag_AverageCharWidth, fe->averageCharWidth());
580     writeTaggedQFixed(QFontEngineQPA::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth()));
581     writeTaggedQFixed(QFontEngineQPA::Tag_LineThickness, fe->lineThickness());
582     writeTaggedQFixed(QFontEngineQPA::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing()));
583     writeTaggedQFixed(QFontEngineQPA::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing()));
584     writeTaggedQFixed(QFontEngineQPA::Tag_UnderlinePosition, fe->underlinePosition());
585     writeTaggedUInt8(QFontEngineQPA::Tag_PixelSize, fe->fontDef.pixelSize);
586     writeTaggedUInt8(QFontEngineQPA::Tag_Weight, fe->fontDef.weight);
587     writeTaggedUInt8(QFontEngineQPA::Tag_Style, fe->fontDef.style);
588
589     writeTaggedUInt8(QFontEngineQPA::Tag_GlyphFormat, QFontEngineQPA::AlphamapGlyphs);
590
591     writeTaggedString(QFontEngineQPA::Tag_EndOfHeader, QByteArray());
592     align4();
593
594     const quint64 size = dev->pos();
595     header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
596     dev->seek(0);
597     dev->write((const char *)&header, sizeof(header));
598     dev->seek(size);
599 }
600
601 void QPAGenerator::writeGMap()
602 {
603     const quint16 glyphCount = fe->glyphCount();
604
605     writeUInt16(QFontEngineQPA::GMapBlock);
606     writeUInt16(0); // padding
607     writeUInt32(glyphCount * 4);
608
609     QByteArray &buffer = dev->buffer();
610     const int numBytes = glyphCount * sizeof(quint32);
611     qint64 pos = buffer.size();
612     buffer.resize(pos + numBytes);
613     qMemSet(buffer.data() + pos, 0xff, numBytes);
614     dev->seek(pos + numBytes);
615 }
616
617 void QPAGenerator::writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data)
618 {
619     writeUInt16(tag);
620     writeUInt16(0); // padding
621     const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
622     writeUInt32(data.size() + padSize);
623     dev->write(data);
624     for (int i = 0; i < padSize; ++i)
625         writeUInt8(0);
626 }
627
628 void QPAGenerator::writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string)
629 {
630     writeUInt16(tag);
631     writeUInt16(string.length());
632     dev->write(string);
633 }
634
635 void QPAGenerator::writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value)
636 {
637     writeUInt16(tag);
638     writeUInt16(sizeof(value));
639     writeUInt32(value);
640 }
641
642 void QPAGenerator::writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value)
643 {
644     writeUInt16(tag);
645     writeUInt16(sizeof(value));
646     writeUInt8(value);
647 }
648
649 void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value)
650 {
651     writeUInt16(tag);
652     writeUInt16(sizeof(quint32));
653     writeUInt32(value.value());
654 }
655
656
657 /*
658     Creates a new multi QPA engine.
659
660     This function takes ownership of the QFontEngine, increasing it's refcount.
661 */
662 QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks)
663     : QFontEngineMulti(fallbacks.size() + 1),
664       fallbackFamilies(fallbacks), script(_script)
665 {
666     Q_ASSERT(fe && fe->type() != QFontEngine::Multi);
667     engines[0] = fe;
668     fe->ref.ref();
669     fontDef = engines[0]->fontDef;
670     setObjectName(QStringLiteral("QFontEngineMultiQPA"));
671 }
672
673 void QFontEngineMultiQPA::loadEngine(int at)
674 {
675     Q_ASSERT(at < engines.size());
676     Q_ASSERT(engines.at(at) == 0);
677
678     QFontDef request = fontDef;
679     request.styleStrategy |= QFont::NoFontMerging;
680     request.family = fallbackFamilies.at(at-1);
681     engines[at] = QFontDatabase::findFont(script,
682                                           /*fontprivate*/0,
683                                           request);
684     Q_ASSERT(engines[at]);
685     engines[at]->ref.ref();
686     engines[at]->fontDef = request;
687 }
688
689 QT_END_NAMESPACE