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