Fix crash due to memory access violation
[profile/ivi/qtbase.git] / src / gui / text / qfontengine_qpa.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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, QFontEngine::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 & QFontEngine::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
387     if (!(flags & GlyphIndicesOnly))
388         recalcAdvances(glyphs, flags);
389
390     return true;
391 }
392
393 void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
394 {
395     for (int i = 0; i < glyphs->numGlyphs; ++i) {
396         const Glyph *g = findGlyph(glyphs->glyphs[i]);
397         if (!g) {
398             glyphs->glyphs[i] = 0;
399             continue;
400         }
401         glyphs->advances_x[i] = g->advance;
402         glyphs->advances_y[i] = 0;
403     }
404 }
405
406 QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g)
407 {
408     const Glyph *glyph = findGlyph(g);
409     if (!glyph)
410         return QImage();
411
412     const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
413
414     QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8);
415
416     return image;
417 }
418
419 void QFontEngineQPA::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
420 {
421     addBitmapFontToPath(x, y, glyphs, path, flags);
422 }
423
424 glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs)
425 {
426     glyph_metrics_t overall;
427     // initialize with line height, we get the same behaviour on all platforms
428     overall.y = -ascent();
429     overall.height = ascent() + descent() + 1;
430
431     QFixed ymax = 0;
432     QFixed xmax = 0;
433     for (int i = 0; i < glyphs.numGlyphs; i++) {
434         const Glyph *g = findGlyph(glyphs.glyphs[i]);
435         if (!g)
436             continue;
437
438         QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
439         QFixed y = overall.yoff + glyphs.offsets[i].y + g->y;
440         overall.x = qMin(overall.x, x);
441         overall.y = qMin(overall.y, y);
442         xmax = qMax(xmax, x + g->width);
443         ymax = qMax(ymax, y + g->height);
444         overall.xoff += g->advance;
445     }
446     overall.height = qMax(overall.height, ymax - overall.y);
447     overall.width = xmax - overall.x;
448
449     return overall;
450 }
451
452 glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph)
453 {
454     glyph_metrics_t overall;
455     const Glyph *g = findGlyph(glyph);
456     if (!g)
457         return overall;
458     overall.x = g->x;
459     overall.y = g->y;
460     overall.width = g->width;
461     overall.height = g->height;
462     overall.xoff = g->advance;
463     return overall;
464 }
465
466 QFixed QFontEngineQPA::ascent() const
467 {
468     return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
469 }
470
471 QFixed QFontEngineQPA::descent() const
472 {
473     return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
474 }
475
476 QFixed QFontEngineQPA::leading() const
477 {
478     return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
479 }
480
481 qreal QFontEngineQPA::maxCharWidth() const
482 {
483     return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
484 }
485
486 qreal QFontEngineQPA::minLeftBearing() const
487 {
488     return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
489 }
490
491 qreal QFontEngineQPA::minRightBearing() const
492 {
493     return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
494 }
495
496 QFixed QFontEngineQPA::underlinePosition() const
497 {
498     return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
499 }
500
501 QFixed QFontEngineQPA::lineThickness() const
502 {
503     return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
504 }
505
506 QFontEngine::Type QFontEngineQPA::type() const
507 {
508     return QFontEngine::QPF2;
509 }
510
511 bool QFontEngineQPA::canRender(const QChar *string, int len)
512 {
513     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
514
515     if (symbol) {
516         for (int i = 0; i < len; ++i) {
517             unsigned int uc = getChar(string, i, len);
518             glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
519             if(!g && uc < 0x100)
520                 g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
521             if (!g)
522                 return false;
523         }
524     } else {
525         for (int i = 0; i < len; ++i) {
526             unsigned int uc = getChar(string, i, len);
527             if (!getTrueTypeGlyphIndex(cmap, uc))
528                 return false;
529         }
530     }
531     return true;
532 }
533
534 bool QFontEngineQPA::isValid() const
535 {
536     return fontData && dataSize && (cmapOffset || externalCMap)
537            && glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
538 }
539
540 void QPAGenerator::generate()
541 {
542     writeHeader();
543     writeGMap();
544     writeBlock(QFontEngineQPA::GlyphBlock, QByteArray());
545
546     dev->seek(4); // position of header.lock
547     writeUInt32(0);
548 }
549
550 void QPAGenerator::writeHeader()
551 {
552     QFontEngineQPA::Header header;
553
554     header.magic[0] = 'Q';
555     header.magic[1] = 'P';
556     header.magic[2] = 'F';
557     header.magic[3] = '2';
558     header.lock = 1;
559     header.majorVersion = QFontEngineQPA::CurrentMajorVersion;
560     header.minorVersion = QFontEngineQPA::CurrentMinorVersion;
561     header.dataSize = 0;
562     dev->write((const char *)&header, sizeof(header));
563
564     writeTaggedString(QFontEngineQPA::Tag_FontName, fe->fontDef.family.toUtf8());
565
566     QFontEngine::FaceId face = fe->faceId();
567     writeTaggedString(QFontEngineQPA::Tag_FileName, face.filename);
568     writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index);
569
570     {
571         uchar data[4];
572         uint len = 4;
573         bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
574         if (ok) {
575             const quint32 revision = qFromBigEndian<quint32>(data);
576             writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision);
577         }
578     }
579
580     writeTaggedQFixed(QFontEngineQPA::Tag_Ascent, fe->ascent());
581     writeTaggedQFixed(QFontEngineQPA::Tag_Descent, fe->descent());
582     writeTaggedQFixed(QFontEngineQPA::Tag_Leading, fe->leading());
583     writeTaggedQFixed(QFontEngineQPA::Tag_XHeight, fe->xHeight());
584     writeTaggedQFixed(QFontEngineQPA::Tag_AverageCharWidth, fe->averageCharWidth());
585     writeTaggedQFixed(QFontEngineQPA::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth()));
586     writeTaggedQFixed(QFontEngineQPA::Tag_LineThickness, fe->lineThickness());
587     writeTaggedQFixed(QFontEngineQPA::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing()));
588     writeTaggedQFixed(QFontEngineQPA::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing()));
589     writeTaggedQFixed(QFontEngineQPA::Tag_UnderlinePosition, fe->underlinePosition());
590     writeTaggedUInt8(QFontEngineQPA::Tag_PixelSize, fe->fontDef.pixelSize);
591     writeTaggedUInt8(QFontEngineQPA::Tag_Weight, fe->fontDef.weight);
592     writeTaggedUInt8(QFontEngineQPA::Tag_Style, fe->fontDef.style);
593
594     writeTaggedUInt8(QFontEngineQPA::Tag_GlyphFormat, QFontEngineQPA::AlphamapGlyphs);
595
596     writeTaggedString(QFontEngineQPA::Tag_EndOfHeader, QByteArray());
597     align4();
598
599     const quint64 size = dev->pos();
600     header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
601     dev->seek(0);
602     dev->write((const char *)&header, sizeof(header));
603     dev->seek(size);
604 }
605
606 void QPAGenerator::writeGMap()
607 {
608     const quint16 glyphCount = fe->glyphCount();
609
610     writeUInt16(QFontEngineQPA::GMapBlock);
611     writeUInt16(0); // padding
612     writeUInt32(glyphCount * 4);
613
614     QByteArray &buffer = dev->buffer();
615     const int numBytes = glyphCount * sizeof(quint32);
616     qint64 pos = buffer.size();
617     buffer.resize(pos + numBytes);
618     memset(buffer.data() + pos, 0xff, numBytes);
619     dev->seek(pos + numBytes);
620 }
621
622 void QPAGenerator::writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data)
623 {
624     writeUInt16(tag);
625     writeUInt16(0); // padding
626     const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
627     writeUInt32(data.size() + padSize);
628     dev->write(data);
629     for (int i = 0; i < padSize; ++i)
630         writeUInt8(0);
631 }
632
633 void QPAGenerator::writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string)
634 {
635     writeUInt16(tag);
636     writeUInt16(string.length());
637     dev->write(string);
638 }
639
640 void QPAGenerator::writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value)
641 {
642     writeUInt16(tag);
643     writeUInt16(sizeof(value));
644     writeUInt32(value);
645 }
646
647 void QPAGenerator::writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value)
648 {
649     writeUInt16(tag);
650     writeUInt16(sizeof(value));
651     writeUInt8(value);
652 }
653
654 void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value)
655 {
656     writeUInt16(tag);
657     writeUInt16(sizeof(quint32));
658     writeUInt32(value.value());
659 }
660
661
662 /*
663     Creates a new multi QPA engine.
664
665     This function takes ownership of the QFontEngine, increasing it's refcount.
666 */
667 QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks)
668     : QFontEngineMulti(fallbacks.size() + 1),
669       fallbackFamilies(fallbacks), script(_script)
670     , fallbacksQueried(true)
671 {
672     init(fe);
673 }
674
675 QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script)
676     : QFontEngineMulti(2)
677     , script(_script)
678     , fallbacksQueried(false)
679 {
680     fallbackFamilies << QString();
681     init(fe);
682 }
683
684 void QFontEngineMultiQPA::init(QFontEngine *fe)
685 {
686     Q_ASSERT(fe && fe->type() != QFontEngine::Multi);
687     engines[0] = fe;
688     fe->ref.ref();
689     fontDef = engines[0]->fontDef;
690     setObjectName(QStringLiteral("QFontEngineMultiQPA"));
691 }
692
693 void QFontEngineMultiQPA::loadEngine(int at)
694 {
695     ensureFallbackFamiliesQueried();
696     Q_ASSERT(at < engines.size());
697     Q_ASSERT(engines.at(at) == 0);
698     QFontDef request = fontDef;
699     request.styleStrategy |= QFont::NoFontMerging;
700     request.family = fallbackFamilies.at(at-1);
701     engines[at] = QFontDatabase::findFont(script,
702                                           /*fontprivate = */0,
703                                           request, /*multi = */false);
704     Q_ASSERT(engines[at]);
705     engines[at]->ref.ref();
706     engines[at]->fontDef = request;
707 }
708 void QFontEngineMultiQPA::ensureFallbackFamiliesQueried()
709 {
710     if (fallbacksQueried)
711         return;
712     QStringList fallbacks = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fallbacksForFamily(engine(0)->fontDef.family, QFont::Style(engine(0)->fontDef.style)
713                                                                                                                      , QFont::AnyStyle, QUnicodeTables::Script(script));
714     setFallbackFamiliesList(fallbacks);
715 }
716
717 void QFontEngineMultiQPA::setFallbackFamiliesList(const QStringList &fallbacks)
718 {
719     // Original FontEngine to restore after the fill.
720     QFontEngine *fe = engines[0];
721     fallbackFamilies = fallbacks;
722     if (!fallbackFamilies.isEmpty()) {
723         engines.fill(0, fallbackFamilies.size() + 1);
724         engines[0] = fe;
725     } else {
726         // Turns out we lied about having any fallback at all.
727         fallbackFamilies << fe->fontDef.family;
728         engines[1] = fe;
729         fe->ref.ref();
730     }
731     fallbacksQueried = true;
732 }
733
734 /*
735   This is used indirectly by QtWebKit when using QTextLayout::setRawFont
736
737   The purpose of this is to provide the necessary font fallbacks when drawing complex
738   text. Since QtWebKit ends up repeatedly creating QTextLayout instances and passing them
739   the same raw font over and over again, we want to cache the corresponding multi font engine
740   as it may contain fallback font engines already.
741 */
742 QFontEngine* QFontEngineMultiQPA::createMultiFontEngine(QFontEngine *fe, int script)
743 {
744     QFontEngine *engine = 0;
745     QFontCache::Key key(fe->fontDef, script, /*multi = */true);
746     QFontCache *fc = QFontCache::instance();
747     //  We can't rely on the fontDef (and hence the cache Key)
748     //  alone to distinguish webfonts, since these should not be
749     //  accidentally shared, even if the resulting fontcache key
750     //  is strictly identical. See:
751     //   http://www.w3.org/TR/css3-fonts/#font-face-rule
752     const bool faceIsLocal = !fe->faceId().filename.isEmpty();
753     QFontCache::EngineCache::Iterator it = fc->engineCache.find(key),
754             end = fc->engineCache.end();
755     while (it != end && it.key() == key) {
756         QFontEngineMulti *cachedEngine = qobject_cast<QFontEngineMulti *>(it.value().data);
757         if (faceIsLocal || (cachedEngine && fe == cachedEngine->engine(0))) {
758             engine = cachedEngine;
759             fc->updateHitCountAndTimeStamp(it.value());
760             break;
761         }
762         it++;
763     }
764     if (!engine) {
765         engine = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fontEngineMulti(fe, QUnicodeTables::Script(script));
766         QFontCache::instance()->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);
767     }
768     Q_ASSERT(engine);
769     return engine;
770 }
771
772 QT_END_NAMESPACE