1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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>
readValue(const uchar * & data)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 
verifyTag(const uchar * tagPtr,const uchar * endPtr)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 
findGlyph(glyph_t g) const151 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 
verifyHeader(const uchar * data,int size)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 
extractHeaderField(const uchar * data,HeaderTag requestedTag)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 
getChar(const QChar * str,int & i,const int len)227 static inline unsigned int getChar(const QChar *str, int &i, const int len)
228 {
229     uint ucs4 = str[i].unicode();
230     if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
231         ++i;
232         ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
233     }
234     return ucs4;
235 }
236 
QFontEngineQPA(const QFontDef & def,const QByteArray & data)237 QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
238     : fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
239 {
240     fontDef = def;
241     cache_cost = 100;
242     externalCMap = 0;
243     cmapOffset = 0;
244     cmapSize = 0;
245     glyphMapOffset = 0;
246     glyphMapEntries = 0;
247     glyphDataOffset = 0;
248     glyphDataSize = 0;
249     kerning_pairs_loaded = false;
250     readOnly = true;
251 
252 #if defined(DEBUG_FONTENGINE)
253     qDebug() << "QFontEngineQPA::QFontEngineQPA( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
254 #endif
255 
256     if (!verifyHeader(fontData, dataSize)) {
257 #if defined(DEBUG_FONTENGINE)
258         qDebug() << "verifyHeader failed!";
259 #endif
260         return;
261     }
262 
263     const Header *header = reinterpret_cast<const Header *>(fontData);
264 
265     readOnly = (header->lock == 0xffffffff);
266 
267     const uchar *imgData = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize);
268     const uchar *endPtr = fontData + dataSize;
269     while (imgData <= endPtr - 8) {
270         quint16 blockTag = readValue<quint16>(imgData);
271         imgData += 2; // skip padding
272         quint32 blockSize = readValue<quint32>(imgData);
273 
274         if (blockTag == CMapBlock) {
275             cmapOffset = imgData - fontData;
276             cmapSize = blockSize;
277         } else if (blockTag == GMapBlock) {
278             glyphMapOffset = imgData - fontData;
279             glyphMapEntries = blockSize / 4;
280         } else if (blockTag == GlyphBlock) {
281             glyphDataOffset = imgData - fontData;
282             glyphDataSize = blockSize;
283         }
284 
285         imgData += blockSize;
286     }
287 
288     face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
289     face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
290 
291     // get the real cmap
292     if (cmapOffset) {
293         int tableSize = cmapSize;
294         const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
295         if (cmapPtr)
296             cmapOffset = cmapPtr - fontData;
297         else
298             cmapOffset = 0;
299     } else if (externalCMap) {
300         int tableSize = cmapSize;
301         externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
302     }
303 
304     // verify all the positions in the glyphMap
305     if (glyphMapOffset) {
306         const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
307         for (uint i = 0; i < glyphMapEntries; ++i) {
308             quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]);
309             if (glyphDataPos == 0xffffffff)
310                 continue;
311             if (glyphDataPos >= glyphDataSize) {
312                 // error
313                 glyphMapOffset = 0;
314                 glyphMapEntries = 0;
315                 break;
316             }
317         }
318     }
319 
320 #if defined(DEBUG_FONTENGINE)
321     if (!isValid())
322         qDebug() << "fontData" <<  fontData << "dataSize" << dataSize
323                  << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
324                  << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
325                  << "fd" << fd << "glyphDataSize" << glyphDataSize;
326 #endif
327 }
328 
~QFontEngineQPA()329 QFontEngineQPA::~QFontEngineQPA()
330 {
331 }
332 
getSfntTableData(uint tag,uchar * buffer,uint * length) const333 bool QFontEngineQPA::getSfntTableData(uint tag, uchar *buffer, uint *length) const
334 {
335     Q_UNUSED(tag);
336     Q_UNUSED(buffer);
337     *length = 0;
338     return false;
339 }
340 
stringToCMap(const QChar * str,int len,QGlyphLayout * glyphs,int * nglyphs,QTextEngine::ShaperFlags flags) const341 bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
342 {
343     if (*nglyphs < len) {
344         *nglyphs = len;
345         return false;
346     }
347 
348 #if defined(DEBUG_FONTENGINE)
349     QSet<QChar> seenGlyphs;
350 #endif
351 
352     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
353 
354     bool mirrored = flags & QTextEngine::RightToLeft;
355     int glyph_pos = 0;
356     if (symbol) {
357         for (int i = 0; i < len; ++i) {
358             unsigned int uc = getChar(str, i, len);
359             if (mirrored)
360                 uc = QChar::mirroredChar(uc);
361             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
362             if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
363                 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
364             ++glyph_pos;
365         }
366     } else {
367         for (int i = 0; i < len; ++i) {
368             unsigned int uc = getChar(str, i, len);
369             if (mirrored)
370                 uc = QChar::mirroredChar(uc);
371             glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
372 #if 0 && defined(DEBUG_FONTENGINE)
373             QChar c(uc);
374             if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
375                 qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
376 
377             seenGlyphs.insert(c);
378 #endif
379             ++glyph_pos;
380         }
381     }
382 
383     *nglyphs = glyph_pos;
384     glyphs->numGlyphs = glyph_pos;
385     recalcAdvances(glyphs, flags);
386     return true;
387 }
388 
recalcAdvances(QGlyphLayout * glyphs,QTextEngine::ShaperFlags) const389 void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
390 {
391     for (int i = 0; i < glyphs->numGlyphs; ++i) {
392         const Glyph *g = findGlyph(glyphs->glyphs[i]);
393         if (!g) {
394             glyphs->glyphs[i] = 0;
395             continue;
396         }
397         glyphs->advances_x[i] = g->advance;
398         glyphs->advances_y[i] = 0;
399     }
400 }
401 
alphaMapForGlyph(glyph_t g)402 QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g)
403 {
404     const Glyph *glyph = findGlyph(g);
405     if (!glyph)
406         return QImage();
407 
408     const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
409 
410     QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8);
411 
412     return image;
413 }
414 
addOutlineToPath(qreal x,qreal y,const QGlyphLayout & glyphs,QPainterPath * path,QTextItem::RenderFlags flags)415 void QFontEngineQPA::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
416 {
417     addBitmapFontToPath(x, y, glyphs, path, flags);
418 }
419 
boundingBox(const QGlyphLayout & glyphs)420 glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs)
421 {
422     glyph_metrics_t overall;
423     // initialize with line height, we get the same behaviour on all platforms
424     overall.y = -ascent();
425     overall.height = ascent() + descent() + 1;
426 
427     QFixed ymax = 0;
428     QFixed xmax = 0;
429     for (int i = 0; i < glyphs.numGlyphs; i++) {
430         const Glyph *g = findGlyph(glyphs.glyphs[i]);
431         if (!g)
432             continue;
433 
434         QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
435         QFixed y = overall.yoff + glyphs.offsets[i].y + g->y;
436         overall.x = qMin(overall.x, x);
437         overall.y = qMin(overall.y, y);
438         xmax = qMax(xmax, x + g->width);
439         ymax = qMax(ymax, y + g->height);
440         overall.xoff += g->advance;
441     }
442     overall.height = qMax(overall.height, ymax - overall.y);
443     overall.width = xmax - overall.x;
444 
445     return overall;
446 }
447 
boundingBox(glyph_t glyph)448 glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph)
449 {
450     glyph_metrics_t overall;
451     const Glyph *g = findGlyph(glyph);
452     if (!g)
453         return overall;
454     overall.x = g->x;
455     overall.y = g->y;
456     overall.width = g->width;
457     overall.height = g->height;
458     overall.xoff = g->advance;
459     return overall;
460 }
461 
ascent() const462 QFixed QFontEngineQPA::ascent() const
463 {
464     return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
465 }
466 
descent() const467 QFixed QFontEngineQPA::descent() const
468 {
469     return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
470 }
471 
leading() const472 QFixed QFontEngineQPA::leading() const
473 {
474     return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
475 }
476 
maxCharWidth() const477 qreal QFontEngineQPA::maxCharWidth() const
478 {
479     return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
480 }
481 
minLeftBearing() const482 qreal QFontEngineQPA::minLeftBearing() const
483 {
484     return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
485 }
486 
minRightBearing() const487 qreal QFontEngineQPA::minRightBearing() const
488 {
489     return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
490 }
491 
underlinePosition() const492 QFixed QFontEngineQPA::underlinePosition() const
493 {
494     return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
495 }
496 
lineThickness() const497 QFixed QFontEngineQPA::lineThickness() const
498 {
499     return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
500 }
501 
type() const502 QFontEngine::Type QFontEngineQPA::type() const
503 {
504     return QFontEngine::QPF2;
505 }
506 
canRender(const QChar * string,int len)507 bool QFontEngineQPA::canRender(const QChar *string, int len)
508 {
509     const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
510 
511     if (symbol) {
512         for (int i = 0; i < len; ++i) {
513             unsigned int uc = getChar(string, i, len);
514             glyph_t g = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
515             if(!g && uc < 0x100)
516                 g = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
517             if (!g)
518                 return false;
519         }
520     } else {
521         for (int i = 0; i < len; ++i) {
522             unsigned int uc = getChar(string, i, len);
523             if (!getTrueTypeGlyphIndex(cmap, cmapSize, uc))
524                 return false;
525         }
526     }
527     return true;
528 }
529 
isValid() const530 bool QFontEngineQPA::isValid() const
531 {
532     return fontData && dataSize && (cmapOffset || externalCMap)
533            && glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
534 }
535 
generate()536 void QPAGenerator::generate()
537 {
538     writeHeader();
539     writeGMap();
540     writeBlock(QFontEngineQPA::GlyphBlock, QByteArray());
541 
542     dev->seek(4); // position of header.lock
543     writeUInt32(0);
544 }
545 
writeHeader()546 void QPAGenerator::writeHeader()
547 {
548     QFontEngineQPA::Header header;
549 
550     header.magic[0] = 'Q';
551     header.magic[1] = 'P';
552     header.magic[2] = 'F';
553     header.magic[3] = '2';
554     header.lock = 1;
555     header.majorVersion = QFontEngineQPA::CurrentMajorVersion;
556     header.minorVersion = QFontEngineQPA::CurrentMinorVersion;
557     header.dataSize = 0;
558     dev->write((const char *)&header, sizeof(header));
559 
560     writeTaggedString(QFontEngineQPA::Tag_FontName, fe->fontDef.family.toUtf8());
561 
562     QFontEngine::FaceId face = fe->faceId();
563     writeTaggedString(QFontEngineQPA::Tag_FileName, face.filename);
564     writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index);
565 
566     {
567         uchar data[4];
568         uint len = 4;
569         bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
570         if (ok) {
571             const quint32 revision = qFromBigEndian<quint32>(data);
572             writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision);
573         }
574     }
575 
576     writeTaggedQFixed(QFontEngineQPA::Tag_Ascent, fe->ascent());
577     writeTaggedQFixed(QFontEngineQPA::Tag_Descent, fe->descent());
578     writeTaggedQFixed(QFontEngineQPA::Tag_Leading, fe->leading());
579     writeTaggedQFixed(QFontEngineQPA::Tag_XHeight, fe->xHeight());
580     writeTaggedQFixed(QFontEngineQPA::Tag_AverageCharWidth, fe->averageCharWidth());
581     writeTaggedQFixed(QFontEngineQPA::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth()));
582     writeTaggedQFixed(QFontEngineQPA::Tag_LineThickness, fe->lineThickness());
583     writeTaggedQFixed(QFontEngineQPA::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing()));
584     writeTaggedQFixed(QFontEngineQPA::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing()));
585     writeTaggedQFixed(QFontEngineQPA::Tag_UnderlinePosition, fe->underlinePosition());
586     writeTaggedUInt8(QFontEngineQPA::Tag_PixelSize, fe->fontDef.pixelSize);
587     writeTaggedUInt8(QFontEngineQPA::Tag_Weight, fe->fontDef.weight);
588     writeTaggedUInt8(QFontEngineQPA::Tag_Style, fe->fontDef.style);
589 
590     writeTaggedUInt8(QFontEngineQPA::Tag_GlyphFormat, QFontEngineQPA::AlphamapGlyphs);
591 
592     writeTaggedString(QFontEngineQPA::Tag_EndOfHeader, QByteArray());
593     align4();
594 
595     const quint64 size = dev->pos();
596     header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
597     dev->seek(0);
598     dev->write((const char *)&header, sizeof(header));
599     dev->seek(size);
600 }
601 
writeGMap()602 void QPAGenerator::writeGMap()
603 {
604     const quint16 glyphCount = fe->glyphCount();
605 
606     writeUInt16(QFontEngineQPA::GMapBlock);
607     writeUInt16(0); // padding
608     writeUInt32(glyphCount * 4);
609 
610     QByteArray &buffer = dev->buffer();
611     const int numBytes = glyphCount * sizeof(quint32);
612     qint64 pos = buffer.size();
613     buffer.resize(pos + numBytes);
614     qMemSet(buffer.data() + pos, 0xff, numBytes);
615     dev->seek(pos + numBytes);
616 }
617 
writeBlock(QFontEngineQPA::BlockTag tag,const QByteArray & data)618 void QPAGenerator::writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data)
619 {
620     writeUInt16(tag);
621     writeUInt16(0); // padding
622     const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
623     writeUInt32(data.size() + padSize);
624     dev->write(data);
625     for (int i = 0; i < padSize; ++i)
626         writeUInt8(0);
627 }
628 
writeTaggedString(QFontEngineQPA::HeaderTag tag,const QByteArray & string)629 void QPAGenerator::writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string)
630 {
631     writeUInt16(tag);
632     writeUInt16(string.length());
633     dev->write(string);
634 }
635 
writeTaggedUInt32(QFontEngineQPA::HeaderTag tag,quint32 value)636 void QPAGenerator::writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value)
637 {
638     writeUInt16(tag);
639     writeUInt16(sizeof(value));
640     writeUInt32(value);
641 }
642 
writeTaggedUInt8(QFontEngineQPA::HeaderTag tag,quint8 value)643 void QPAGenerator::writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value)
644 {
645     writeUInt16(tag);
646     writeUInt16(sizeof(value));
647     writeUInt8(value);
648 }
649 
writeTaggedQFixed(QFontEngineQPA::HeaderTag tag,QFixed value)650 void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value)
651 {
652     writeUInt16(tag);
653     writeUInt16(sizeof(quint32));
654     writeUInt32(value.value());
655 }
656 
657 
658 /*
659     Creates a new multi QPA engine.
660 
661     This function takes ownership of the QFontEngine, increasing it's refcount.
662 */
QFontEngineMultiQPA(QFontEngine * fe,int _script,const QStringList & fallbacks)663 QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks)
664     : QFontEngineMulti(fallbacks.size() + 1),
665       fallbackFamilies(fallbacks), script(_script)
666 {
667     engines[0] = fe;
668     fe->ref.ref();
669     fontDef = engines[0]->fontDef;
670 }
671 
loadEngine(int at)672 void QFontEngineMultiQPA::loadEngine(int at)
673 {
674     Q_ASSERT(at < engines.size());
675     Q_ASSERT(engines.at(at) == 0);
676 
677     QFontDef request = fontDef;
678     request.styleStrategy |= QFont::NoFontMerging;
679     request.family = fallbackFamilies.at(at-1);
680     engines[at] = QFontDatabase::findFont(script,
681                                           /*fontprivate*/0,
682                                           request);
683     Q_ASSERT(engines[at]);
684     engines[at]->ref.ref();
685     engines[at]->fontDef = request;
686 }
687 
688 QT_END_NAMESPACE
689