Compile with clang when C++11 support is enabled
[profile/ivi/qtbase.git] / src / gui / text / qfontengine_qpa.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_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/qpaintengine_raster_p.h>
50 #include <QtGui/private/qguiapplication_p.h>
51 #include <qpa/qplatformfontdatabase.h>
52 #include <qpa/qplatformintegration.h>
53
54 QT_BEGIN_NAMESPACE
55
56 //#define DEBUG_HEADER
57 //#define DEBUG_FONTENGINE
58
59 static QFontEngineQPA::TagType tagTypes[QFontEngineQPA::NumTags] = {
60     QFontEngineQPA::StringType, // FontName
61     QFontEngineQPA::StringType, // FileName
62     QFontEngineQPA::UInt32Type, // FileIndex
63     QFontEngineQPA::UInt32Type, // FontRevision
64     QFontEngineQPA::StringType, // FreeText
65     QFontEngineQPA::FixedType,  // Ascent
66     QFontEngineQPA::FixedType,  // Descent
67     QFontEngineQPA::FixedType,  // Leading
68     QFontEngineQPA::FixedType,  // XHeight
69     QFontEngineQPA::FixedType,  // AverageCharWidth
70     QFontEngineQPA::FixedType,  // MaxCharWidth
71     QFontEngineQPA::FixedType,  // LineThickness
72     QFontEngineQPA::FixedType,  // MinLeftBearing
73     QFontEngineQPA::FixedType,  // MinRightBearing
74     QFontEngineQPA::FixedType,  // UnderlinePosition
75     QFontEngineQPA::UInt8Type,  // GlyphFormat
76     QFontEngineQPA::UInt8Type,  // PixelSize
77     QFontEngineQPA::UInt8Type,  // Weight
78     QFontEngineQPA::UInt8Type,  // Style
79     QFontEngineQPA::StringType, // EndOfHeader
80     QFontEngineQPA::BitFieldType// WritingSystems
81 };
82
83
84 #if defined(DEBUG_HEADER)
85 # define DEBUG_VERIFY qDebug
86 #else
87 # define DEBUG_VERIFY if (0) qDebug
88 #endif
89
90 #define READ_VERIFY(type, variable) \
91     if (tagPtr + sizeof(type) > endPtr) { \
92         DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \
93         return 0; \
94     } \
95     variable = qFromBigEndian<type>(tagPtr); \
96     DEBUG_VERIFY() << "read value" << variable << "of type " #type; \
97     tagPtr += sizeof(type)
98
99 template <typename T>
100 T readValue(const uchar *&data)
101 {
102     T value = qFromBigEndian<T>(data);
103     data += sizeof(T);
104     return value;
105 }
106
107 #define VERIFY(condition) \
108     if (!(condition)) { \
109         DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \
110         return 0; \
111     }
112
113 #define VERIFY_TAG(condition) \
114     if (!(condition)) { \
115         DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \
116         return 0; \
117     }
118
119 static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr)
120 {
121     quint16 tag, length;
122     READ_VERIFY(quint16, tag);
123     READ_VERIFY(quint16, length);
124     if (tag == QFontEngineQPA::Tag_EndOfHeader)
125         return endPtr;
126     if (tag < QFontEngineQPA::NumTags) {
127         switch (tagTypes[tag]) {
128             case QFontEngineQPA::BitFieldType:
129             case QFontEngineQPA::StringType:
130                 // can't do anything...
131                 break;
132             case QFontEngineQPA::UInt32Type:
133                 VERIFY_TAG(length == sizeof(quint32));
134                 break;
135             case QFontEngineQPA::FixedType:
136                 VERIFY_TAG(length == sizeof(quint32));
137                 break;
138             case QFontEngineQPA::UInt8Type:
139                 VERIFY_TAG(length == sizeof(quint8));
140                 break;
141         }
142 #if defined(DEBUG_HEADER)
143         if (length == 1)
144             qDebug() << "tag data" << hex << *tagPtr;
145         else if (length == 4)
146             qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
147 #endif
148     }
149     return tagPtr + length;
150 }
151
152 const QFontEngineQPA::Glyph *QFontEngineQPA::findGlyph(glyph_t g) const
153 {
154     if (!g || g >= glyphMapEntries)
155         return 0;
156     const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
157     quint32 glyphPos = qFromBigEndian<quint32>(gmapPtr[g]);
158     if (glyphPos > glyphDataSize) {
159         if (glyphPos == 0xffffffff)
160             return 0;
161 #if defined(DEBUG_FONTENGINE)
162         qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
163 #endif
164         if (glyphPos > glyphDataSize)
165             return 0;
166     }
167     return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
168 }
169
170 bool QFontEngineQPA::verifyHeader(const uchar *data, int size)
171 {
172     VERIFY(size >= int(sizeof(Header)));
173     const Header *header = reinterpret_cast<const Header *>(data);
174     if (header->magic[0] != 'Q'
175         || header->magic[1] != 'P'
176         || header->magic[2] != 'F'
177         || header->magic[3] != '2')
178         return false;
179
180     VERIFY(header->majorVersion <= CurrentMajorVersion);
181     const quint16 dataSize = qFromBigEndian<quint16>(header->dataSize);
182     VERIFY(size >= int(sizeof(Header)) + dataSize);
183
184     const uchar *tagPtr = data + sizeof(Header);
185     const uchar *tagEndPtr = tagPtr + dataSize;
186     while (tagPtr < tagEndPtr - 3) {
187         tagPtr = verifyTag(tagPtr, tagEndPtr);
188         VERIFY(tagPtr);
189     }
190
191     VERIFY(tagPtr <= tagEndPtr);
192     return true;
193 }
194
195 QVariant QFontEngineQPA::extractHeaderField(const uchar *data, HeaderTag requestedTag)
196 {
197     const Header *header = reinterpret_cast<const Header *>(data);
198     const uchar *tagPtr = data + sizeof(Header);
199     const uchar *endPtr = tagPtr + qFromBigEndian<quint16>(header->dataSize);
200     while (tagPtr < endPtr - 3) {
201         quint16 tag = readValue<quint16>(tagPtr);
202         quint16 length = readValue<quint16>(tagPtr);
203         if (tag == requestedTag) {
204             switch (tagTypes[requestedTag]) {
205                 case StringType:
206                     return QVariant(QString::fromUtf8(reinterpret_cast<const char *>(tagPtr), length));
207                 case UInt32Type:
208                     return QVariant(readValue<quint32>(tagPtr));
209                 case UInt8Type:
210                     return QVariant(uint(*tagPtr));
211                 case FixedType:
212                     return QVariant(QFixed::fromFixed(readValue<quint32>(tagPtr)).toReal());
213                 case BitFieldType:
214                     return QVariant(QByteArray(reinterpret_cast<const char *>(tagPtr), length));
215             }
216             return QVariant();
217         } else if (tag == Tag_EndOfHeader) {
218             break;
219         }
220         tagPtr += length;
221     }
222
223     return QVariant();
224 }
225
226
227
228 static inline unsigned int getChar(const QChar *str, int &i, const int len)
229 {
230     uint ucs4 = str[i].unicode();
231     if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
232         ++i;
233         ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
234     }
235     return ucs4;
236 }
237
238 QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
239     : fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
240 {
241     fontDef = def;
242     cache_cost = 100;
243     externalCMap = 0;
244     cmapOffset = 0;
245     cmapSize = 0;
246     glyphMapOffset = 0;
247     glyphMapEntries = 0;
248     glyphDataOffset = 0;
249     glyphDataSize = 0;
250     kerning_pairs_loaded = false;
251     readOnly = true;
252
253 #if defined(DEBUG_FONTENGINE)
254     qDebug() << "QFontEngineQPA::QFontEngineQPA( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
255 #endif
256
257     if (!verifyHeader(fontData, dataSize)) {
258 #if defined(DEBUG_FONTENGINE)
259         qDebug() << "verifyHeader failed!";
260 #endif
261         return;
262     }
263
264     const Header *header = reinterpret_cast<const Header *>(fontData);
265
266     readOnly = (header->lock == 0xffffffff);
267
268     const uchar *imgData = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize);
269     const uchar *endPtr = fontData + dataSize;
270     while (imgData <= endPtr - 8) {
271         quint16 blockTag = readValue<quint16>(imgData);
272         imgData += 2; // skip padding
273         quint32 blockSize = readValue<quint32>(imgData);
274
275         if (blockTag == CMapBlock) {
276             cmapOffset = imgData - fontData;
277             cmapSize = blockSize;
278         } else if (blockTag == GMapBlock) {
279             glyphMapOffset = imgData - fontData;
280             glyphMapEntries = blockSize / 4;
281         } else if (blockTag == GlyphBlock) {
282             glyphDataOffset = imgData - fontData;
283             glyphDataSize = blockSize;
284         }
285
286         imgData += blockSize;
287     }
288
289     face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
290     face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
291
292     // get the real cmap
293     if (cmapOffset) {
294         int tableSize = cmapSize;
295         const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
296         if (cmapPtr)
297             cmapOffset = cmapPtr - fontData;
298         else
299             cmapOffset = 0;
300     } else if (externalCMap) {
301         int tableSize = cmapSize;
302         externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
303     }
304
305     // verify all the positions in the glyphMap
306     if (glyphMapOffset) {
307         const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
308         for (uint i = 0; i < glyphMapEntries; ++i) {
309             quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]);
310             if (glyphDataPos == 0xffffffff)
311                 continue;
312             if (glyphDataPos >= glyphDataSize) {
313                 // error
314                 glyphMapOffset = 0;
315                 glyphMapEntries = 0;
316                 break;
317             }
318         }
319     }
320
321 #if defined(DEBUG_FONTENGINE)
322     if (!isValid())
323         qDebug() << "fontData" <<  fontData << "dataSize" << dataSize
324                  << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
325                  << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
326                  << "fd" << fd << "glyphDataSize" << glyphDataSize;
327 #endif
328 }
329
330 QFontEngineQPA::~QFontEngineQPA()
331 {
332 }
333
334 bool QFontEngineQPA::getSfntTableData(uint tag, uchar *buffer, uint *length) const
335 {
336     Q_UNUSED(tag);
337     Q_UNUSED(buffer);
338     *length = 0;
339     return false;
340 }
341
342 bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
343 {
344     if (*nglyphs < len) {
345         *nglyphs = len;
346         return false;
347     }
348
349 #if defined(DEBUG_FONTENGINE)
350     QSet<QChar> seenGlyphs;
351 #endif
352
353     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
354
355     bool mirrored = flags & QTextEngine::RightToLeft;
356     int glyph_pos = 0;
357     if (symbol) {
358         for (int i = 0; i < len; ++i) {
359             unsigned int uc = getChar(str, i, len);
360             if (mirrored)
361                 uc = QChar::mirroredChar(uc);
362             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
363             if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
364                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
365             ++glyph_pos;
366         }
367     } else {
368         for (int i = 0; i < len; ++i) {
369             unsigned int uc = getChar(str, i, len);
370             if (mirrored)
371                 uc = QChar::mirroredChar(uc);
372             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
373 #if 0 && defined(DEBUG_FONTENGINE)
374             QChar c(uc);
375             if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
376                 qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
377
378             seenGlyphs.insert(c);
379 #endif
380             ++glyph_pos;
381         }
382     }
383
384     *nglyphs = glyph_pos;
385     glyphs->numGlyphs = glyph_pos;
386     recalcAdvances(glyphs, flags);
387     return true;
388 }
389
390 void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
391 {
392     for (int i = 0; i < glyphs->numGlyphs; ++i) {
393         const Glyph *g = findGlyph(glyphs->glyphs[i]);
394         if (!g) {
395             glyphs->glyphs[i] = 0;
396             continue;
397         }
398         glyphs->advances_x[i] = g->advance;
399         glyphs->advances_y[i] = 0;
400     }
401 }
402
403 QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g)
404 {
405     const Glyph *glyph = findGlyph(g);
406     if (!glyph)
407         return QImage();
408
409     const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
410
411     QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8);
412
413     return image;
414 }
415
416 void QFontEngineQPA::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
417 {
418     addBitmapFontToPath(x, y, glyphs, path, flags);
419 }
420
421 glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs)
422 {
423     glyph_metrics_t overall;
424     // initialize with line height, we get the same behaviour on all platforms
425     overall.y = -ascent();
426     overall.height = ascent() + descent() + 1;
427
428     QFixed ymax = 0;
429     QFixed xmax = 0;
430     for (int i = 0; i < glyphs.numGlyphs; i++) {
431         const Glyph *g = findGlyph(glyphs.glyphs[i]);
432         if (!g)
433             continue;
434
435         QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
436         QFixed y = overall.yoff + glyphs.offsets[i].y + g->y;
437         overall.x = qMin(overall.x, x);
438         overall.y = qMin(overall.y, y);
439         xmax = qMax(xmax, x + g->width);
440         ymax = qMax(ymax, y + g->height);
441         overall.xoff += g->advance;
442     }
443     overall.height = qMax(overall.height, ymax - overall.y);
444     overall.width = xmax - overall.x;
445
446     return overall;
447 }
448
449 glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph)
450 {
451     glyph_metrics_t overall;
452     const Glyph *g = findGlyph(glyph);
453     if (!g)
454         return overall;
455     overall.x = g->x;
456     overall.y = g->y;
457     overall.width = g->width;
458     overall.height = g->height;
459     overall.xoff = g->advance;
460     return overall;
461 }
462
463 QFixed QFontEngineQPA::ascent() const
464 {
465     return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
466 }
467
468 QFixed QFontEngineQPA::descent() const
469 {
470     return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
471 }
472
473 QFixed QFontEngineQPA::leading() const
474 {
475     return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
476 }
477
478 qreal QFontEngineQPA::maxCharWidth() const
479 {
480     return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
481 }
482
483 qreal QFontEngineQPA::minLeftBearing() const
484 {
485     return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
486 }
487
488 qreal QFontEngineQPA::minRightBearing() const
489 {
490     return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
491 }
492
493 QFixed QFontEngineQPA::underlinePosition() const
494 {
495     return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
496 }
497
498 QFixed QFontEngineQPA::lineThickness() const
499 {
500     return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
501 }
502
503 QFontEngine::Type QFontEngineQPA::type() const
504 {
505     return QFontEngine::QPF2;
506 }
507
508 bool QFontEngineQPA::canRender(const QChar *string, int len)
509 {
510     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
511
512     if (symbol) {
513         for (int i = 0; i < len; ++i) {
514             unsigned int uc = getChar(string, i, len);
515             glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
516             if(!g && uc < 0x100)
517                 g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
518             if (!g)
519                 return false;
520         }
521     } else {
522         for (int i = 0; i < len; ++i) {
523             unsigned int uc = getChar(string, i, len);
524             if (!getTrueTypeGlyphIndex(cmap, uc))
525                 return false;
526         }
527     }
528     return true;
529 }
530
531 bool QFontEngineQPA::isValid() const
532 {
533     return fontData && dataSize && (cmapOffset || externalCMap)
534            && glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
535 }
536
537 void QPAGenerator::generate()
538 {
539     writeHeader();
540     writeGMap();
541     writeBlock(QFontEngineQPA::GlyphBlock, QByteArray());
542
543     dev->seek(4); // position of header.lock
544     writeUInt32(0);
545 }
546
547 void QPAGenerator::writeHeader()
548 {
549     QFontEngineQPA::Header header;
550
551     header.magic[0] = 'Q';
552     header.magic[1] = 'P';
553     header.magic[2] = 'F';
554     header.magic[3] = '2';
555     header.lock = 1;
556     header.majorVersion = QFontEngineQPA::CurrentMajorVersion;
557     header.minorVersion = QFontEngineQPA::CurrentMinorVersion;
558     header.dataSize = 0;
559     dev->write((const char *)&header, sizeof(header));
560
561     writeTaggedString(QFontEngineQPA::Tag_FontName, fe->fontDef.family.toUtf8());
562
563     QFontEngine::FaceId face = fe->faceId();
564     writeTaggedString(QFontEngineQPA::Tag_FileName, face.filename);
565     writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index);
566
567     {
568         uchar data[4];
569         uint len = 4;
570         bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
571         if (ok) {
572             const quint32 revision = qFromBigEndian<quint32>(data);
573             writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision);
574         }
575     }
576
577     writeTaggedQFixed(QFontEngineQPA::Tag_Ascent, fe->ascent());
578     writeTaggedQFixed(QFontEngineQPA::Tag_Descent, fe->descent());
579     writeTaggedQFixed(QFontEngineQPA::Tag_Leading, fe->leading());
580     writeTaggedQFixed(QFontEngineQPA::Tag_XHeight, fe->xHeight());
581     writeTaggedQFixed(QFontEngineQPA::Tag_AverageCharWidth, fe->averageCharWidth());
582     writeTaggedQFixed(QFontEngineQPA::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth()));
583     writeTaggedQFixed(QFontEngineQPA::Tag_LineThickness, fe->lineThickness());
584     writeTaggedQFixed(QFontEngineQPA::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing()));
585     writeTaggedQFixed(QFontEngineQPA::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing()));
586     writeTaggedQFixed(QFontEngineQPA::Tag_UnderlinePosition, fe->underlinePosition());
587     writeTaggedUInt8(QFontEngineQPA::Tag_PixelSize, fe->fontDef.pixelSize);
588     writeTaggedUInt8(QFontEngineQPA::Tag_Weight, fe->fontDef.weight);
589     writeTaggedUInt8(QFontEngineQPA::Tag_Style, fe->fontDef.style);
590
591     writeTaggedUInt8(QFontEngineQPA::Tag_GlyphFormat, QFontEngineQPA::AlphamapGlyphs);
592
593     writeTaggedString(QFontEngineQPA::Tag_EndOfHeader, QByteArray());
594     align4();
595
596     const quint64 size = dev->pos();
597     header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
598     dev->seek(0);
599     dev->write((const char *)&header, sizeof(header));
600     dev->seek(size);
601 }
602
603 void QPAGenerator::writeGMap()
604 {
605     const quint16 glyphCount = fe->glyphCount();
606
607     writeUInt16(QFontEngineQPA::GMapBlock);
608     writeUInt16(0); // padding
609     writeUInt32(glyphCount * 4);
610
611     QByteArray &buffer = dev->buffer();
612     const int numBytes = glyphCount * sizeof(quint32);
613     qint64 pos = buffer.size();
614     buffer.resize(pos + numBytes);
615     memset(buffer.data() + pos, 0xff, numBytes);
616     dev->seek(pos + numBytes);
617 }
618
619 void QPAGenerator::writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data)
620 {
621     writeUInt16(tag);
622     writeUInt16(0); // padding
623     const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
624     writeUInt32(data.size() + padSize);
625     dev->write(data);
626     for (int i = 0; i < padSize; ++i)
627         writeUInt8(0);
628 }
629
630 void QPAGenerator::writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string)
631 {
632     writeUInt16(tag);
633     writeUInt16(string.length());
634     dev->write(string);
635 }
636
637 void QPAGenerator::writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value)
638 {
639     writeUInt16(tag);
640     writeUInt16(sizeof(value));
641     writeUInt32(value);
642 }
643
644 void QPAGenerator::writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value)
645 {
646     writeUInt16(tag);
647     writeUInt16(sizeof(value));
648     writeUInt8(value);
649 }
650
651 void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value)
652 {
653     writeUInt16(tag);
654     writeUInt16(sizeof(quint32));
655     writeUInt32(value.value());
656 }
657
658
659 /*
660     Creates a new multi QPA engine.
661
662     This function takes ownership of the QFontEngine, increasing it's refcount.
663 */
664 QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks)
665     : QFontEngineMulti(fallbacks.size() + 1),
666       fallbackFamilies(fallbacks), script(_script)
667     , fallbacksQueried(true)
668 {
669     init(fe);
670 }
671
672 QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script)
673     : QFontEngineMulti(2)
674     , script(_script)
675     , fallbacksQueried(false)
676 {
677     fallbackFamilies << QString();
678     init(fe);
679 }
680
681 void QFontEngineMultiQPA::init(QFontEngine *fe)
682 {
683     Q_ASSERT(fe && fe->type() != QFontEngine::Multi);
684     engines[0] = fe;
685     fe->ref.ref();
686     fontDef = engines[0]->fontDef;
687     setObjectName(QStringLiteral("QFontEngineMultiQPA"));
688 }
689
690 void QFontEngineMultiQPA::loadEngine(int at)
691 {
692     ensureFallbackFamiliesQueried();
693     Q_ASSERT(at < engines.size());
694     Q_ASSERT(engines.at(at) == 0);
695     QFontDef request = fontDef;
696     request.styleStrategy |= QFont::NoFontMerging;
697     request.family = fallbackFamilies.at(at-1);
698     engines[at] = QFontDatabase::findFont(script,
699                                           /*fontprivate = */0,
700                                           request, /*multi = */false);
701     Q_ASSERT(engines[at]);
702     engines[at]->ref.ref();
703     engines[at]->fontDef = request;
704 }
705 void QFontEngineMultiQPA::ensureFallbackFamiliesQueried()
706 {
707     if (fallbacksQueried)
708         return;
709     QStringList fallbacks = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fallbacksForFamily(engine(0)->fontDef.family, QFont::Style(engine(0)->fontDef.style)
710                                                                                                                      , QFont::AnyStyle, QUnicodeTables::Script(script));
711     setFallbackFamiliesList(fallbacks);
712 }
713
714 void QFontEngineMultiQPA::setFallbackFamiliesList(const QStringList &fallbacks)
715 {
716     // Original FontEngine to restore after the fill.
717     QFontEngine *fe = engines[0];
718     fallbackFamilies = fallbacks;
719     if (!fallbackFamilies.isEmpty()) {
720         engines.fill(0, fallbackFamilies.size() + 1);
721         engines[0] = fe;
722     } else {
723         // Turns out we lied about having any fallback at all.
724         fallbackFamilies << fe->fontDef.family;
725         engines[1] = fe;
726     }
727     fallbacksQueried = true;
728 }
729
730 /*
731   This is used indirectly by QtWebKit when using QTextLayout::setRawFont
732
733   The purpose of this is to provide the necessary font fallbacks when drawing complex
734   text. Since QtWebKit ends up repeatedly creating QTextLayout instances and passing them
735   the same raw font over and over again, we want to cache the corresponding multi font engine
736   as it may contain fallback font engines already.
737 */
738 QFontEngine* QFontEngineMultiQPA::createMultiFontEngine(QFontEngine *fe, int script)
739 {
740     QFontEngine *engine = 0;
741     QFontCache::Key key(fe->fontDef, script, /*multi = */true);
742     QFontCache *fc = QFontCache::instance();
743     //  We can't rely on the fontDef (and hence the cache Key)
744     //  alone to distinguish webfonts, since these should not be
745     //  accidentally shared, even if the resulting fontcache key
746     //  is strictly identical. See:
747     //   http://www.w3.org/TR/css3-fonts/#font-face-rule
748     const bool faceIsLocal = !fe->faceId().filename.isEmpty();
749     QFontCache::EngineCache::Iterator it = fc->engineCache.find(key),
750             end = fc->engineCache.end();
751     while (it != end && it.key() == key) {
752         QFontEngineMulti *cachedEngine = qobject_cast<QFontEngineMulti *>(it.value().data);
753         if (faceIsLocal || (cachedEngine && fe == cachedEngine->engine(0))) {
754             engine = cachedEngine;
755             fc->updateHitCountAndTimeStamp(it.value());
756             break;
757         }
758         it++;
759     }
760     if (!engine) {
761         engine = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fontEngineMulti(fe, QUnicodeTables::Script(script));
762         QFontCache::instance()->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);
763     }
764     Q_ASSERT(engine);
765     return engine;
766 }
767
768 QT_END_NAMESPACE