1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qfontengine_qpf2_p.h"
41
42 #include <QtCore/QFile>
43 #include <QtCore/QFileInfo>
44 #include <QtCore/QDir>
45 #include <QtCore/QBuffer>
46 #include <QtCore/private/qstringiterator_p.h>
47
48 #include <QtGui/private/qpaintengine_raster_p.h>
49 #include <QtGui/private/qguiapplication_p.h>
50 #include <qpa/qplatformfontdatabase.h>
51 #include <qpa/qplatformintegration.h>
52
53 QT_BEGIN_NAMESPACE
54
55 //#define DEBUG_HEADER
56 //#define DEBUG_FONTENGINE
57
58 static const QFontEngineQPF2::TagType tagTypes[QFontEngineQPF2::NumTags] = {
59 QFontEngineQPF2::StringType, // FontName
60 QFontEngineQPF2::StringType, // FileName
61 QFontEngineQPF2::UInt32Type, // FileIndex
62 QFontEngineQPF2::UInt32Type, // FontRevision
63 QFontEngineQPF2::StringType, // FreeText
64 QFontEngineQPF2::FixedType, // Ascent
65 QFontEngineQPF2::FixedType, // Descent
66 QFontEngineQPF2::FixedType, // Leading
67 QFontEngineQPF2::FixedType, // XHeight
68 QFontEngineQPF2::FixedType, // AverageCharWidth
69 QFontEngineQPF2::FixedType, // MaxCharWidth
70 QFontEngineQPF2::FixedType, // LineThickness
71 QFontEngineQPF2::FixedType, // MinLeftBearing
72 QFontEngineQPF2::FixedType, // MinRightBearing
73 QFontEngineQPF2::FixedType, // UnderlinePosition
74 QFontEngineQPF2::UInt8Type, // GlyphFormat
75 QFontEngineQPF2::UInt8Type, // PixelSize
76 QFontEngineQPF2::UInt8Type, // Weight
77 QFontEngineQPF2::UInt8Type, // Style
78 QFontEngineQPF2::StringType, // EndOfHeader
79 QFontEngineQPF2::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 == QFontEngineQPF2::Tag_EndOfHeader)
124 return endPtr;
125 if (tag < QFontEngineQPF2::NumTags) {
126 switch (tagTypes[tag]) {
127 case QFontEngineQPF2::BitFieldType:
128 case QFontEngineQPF2::StringType:
129 // can't do anything...
130 break;
131 case QFontEngineQPF2::UInt32Type:
132 VERIFY_TAG(length == sizeof(quint32));
133 break;
134 case QFontEngineQPF2::FixedType:
135 VERIFY_TAG(length == sizeof(quint32));
136 break;
137 case QFontEngineQPF2::UInt8Type:
138 VERIFY_TAG(length == sizeof(quint8));
139 break;
140 }
141 #if defined(DEBUG_HEADER)
142 if (length == 1)
143 qDebug() << "tag data" << Qt::hex << *tagPtr;
144 else if (length == 4)
145 qDebug() << "tag data" << Qt::hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
146 #endif
147 }
148 return tagPtr + length;
149 }
150
findGlyph(glyph_t g) const151 const QFontEngineQPF2::Glyph *QFontEngineQPF2::findGlyph(glyph_t g) const
152 {
153 if (!g || g >= glyphMapEntries)
154 return nullptr;
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 nullptr;
160 #if defined(DEBUG_FONTENGINE)
161 qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
162 #endif
163 if (glyphPos > glyphDataSize)
164 return nullptr;
165 }
166 return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
167 }
168
verifyHeader(const uchar * data,int size)169 bool QFontEngineQPF2::verifyHeader(const uchar *data, int size)
170 {
171 VERIFY(quintptr(data) % Q_ALIGNOF(Header) == 0);
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
extractHeaderField(const uchar * data,HeaderTag requestedTag)195 QVariant QFontEngineQPF2::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
QFontEngineQPF2(const QFontDef & def,const QByteArray & data)227 QFontEngineQPF2::QFontEngineQPF2(const QFontDef &def, const QByteArray &data)
228 : QFontEngine(QPF2),
229 fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
230 {
231 fontDef = def;
232 cache_cost = 100;
233 cmap = nullptr;
234 cmapOffset = 0;
235 cmapSize = 0;
236 glyphMapOffset = 0;
237 glyphMapEntries = 0;
238 glyphDataOffset = 0;
239 glyphDataSize = 0;
240 kerning_pairs_loaded = false;
241 readOnly = true;
242
243 #if defined(DEBUG_FONTENGINE)
244 qDebug() << "QFontEngineQPF2::QFontEngineQPF2( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
245 #endif
246
247 if (!verifyHeader(fontData, dataSize)) {
248 #if defined(DEBUG_FONTENGINE)
249 qDebug("verifyHeader failed!");
250 #endif
251 return;
252 }
253
254 const Header *header = reinterpret_cast<const Header *>(fontData);
255
256 readOnly = (header->lock == 0xffffffff);
257
258 const uchar *imgData = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize);
259 const uchar *endPtr = fontData + dataSize;
260 while (imgData <= endPtr - 8) {
261 quint16 blockTag = readValue<quint16>(imgData);
262 imgData += 2; // skip padding
263 quint32 blockSize = readValue<quint32>(imgData);
264
265 if (blockTag == CMapBlock) {
266 cmapOffset = imgData - fontData;
267 cmapSize = blockSize;
268 } else if (blockTag == GMapBlock) {
269 glyphMapOffset = imgData - fontData;
270 glyphMapEntries = blockSize / 4;
271 } else if (blockTag == GlyphBlock) {
272 glyphDataOffset = imgData - fontData;
273 glyphDataSize = blockSize;
274 }
275
276 imgData += blockSize;
277 }
278
279 face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
280 face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
281
282 // get the real cmap
283 if (cmapOffset) {
284 cmap = QFontEngine::getCMap(fontData + cmapOffset, cmapSize, &symbol, &cmapSize);
285 cmapOffset = cmap ? cmap - fontData : 0;
286 }
287
288 // verify all the positions in the glyphMap
289 if (glyphMapOffset) {
290 const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
291 for (uint i = 0; i < glyphMapEntries; ++i) {
292 quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]);
293 if (glyphDataPos == 0xffffffff)
294 continue;
295 if (glyphDataPos >= glyphDataSize) {
296 // error
297 glyphMapOffset = 0;
298 glyphMapEntries = 0;
299 break;
300 }
301 }
302 }
303
304 #if defined(DEBUG_FONTENGINE)
305 if (!isValid())
306 qDebug() << "fontData" << fontData << "dataSize" << dataSize
307 << "cmap" << cmap << "cmapOffset" << cmapOffset
308 << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
309 << "fd" << fd << "glyphDataSize" << glyphDataSize;
310 #endif
311 }
312
~QFontEngineQPF2()313 QFontEngineQPF2::~QFontEngineQPF2()
314 {
315 }
316
getSfntTableData(uint tag,uchar * buffer,uint * length) const317 bool QFontEngineQPF2::getSfntTableData(uint tag, uchar *buffer, uint *length) const
318 {
319 if (tag != MAKE_TAG('c', 'm', 'a', 'p') || !cmap)
320 return false;
321
322 if (buffer && int(*length) >= cmapSize)
323 memcpy(buffer, cmap, cmapSize);
324 *length = cmapSize;
325 Q_ASSERT(int(*length) > 0);
326 return true;
327 }
328
glyphIndex(uint ucs4) const329 glyph_t QFontEngineQPF2::glyphIndex(uint ucs4) const
330 {
331 glyph_t glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4);
332 if (glyph == 0 && symbol && ucs4 < 0x100)
333 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000);
334 if (!findGlyph(glyph))
335 glyph = 0;
336
337 return glyph;
338 }
339
stringToCMap(const QChar * str,int len,QGlyphLayout * glyphs,int * nglyphs,QFontEngine::ShaperFlags flags) const340 bool QFontEngineQPF2::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
341 {
342 Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
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 int glyph_pos = 0;
353 if (symbol) {
354 QStringIterator it(str, str + len);
355 while (it.hasNext()) {
356 const uint uc = it.next();
357 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
358 if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
359 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
360 ++glyph_pos;
361 }
362 } else {
363 QStringIterator it(str, str + len);
364 while (it.hasNext()) {
365 const uint uc = it.next();
366 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
367 #if 0 && defined(DEBUG_FONTENGINE)
368 QChar c(uc);
369 if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
370 qDebug() << "glyph for character" << c << '/' << Qt::hex << uc << "is" << Qt::dec << glyphs[glyph_pos].glyph;
371
372 seenGlyphs.insert(c);
373 #endif
374 ++glyph_pos;
375 }
376 }
377
378 *nglyphs = glyph_pos;
379 glyphs->numGlyphs = glyph_pos;
380
381 if (!(flags & GlyphIndicesOnly))
382 recalcAdvances(glyphs, flags);
383
384 return true;
385 }
386
recalcAdvances(QGlyphLayout * glyphs,QFontEngine::ShaperFlags) const387 void QFontEngineQPF2::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
388 {
389 for (int i = 0; i < glyphs->numGlyphs; ++i) {
390 const Glyph *g = findGlyph(glyphs->glyphs[i]);
391 if (!g)
392 continue;
393 glyphs->advances[i] = g->advance;
394 }
395 }
396
alphaMapForGlyph(glyph_t g)397 QImage QFontEngineQPF2::alphaMapForGlyph(glyph_t g)
398 {
399 const Glyph *glyph = findGlyph(g);
400 if (!glyph)
401 return QImage();
402
403 const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
404
405 QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Alpha8);
406
407 return image;
408 }
409
addOutlineToPath(qreal x,qreal y,const QGlyphLayout & glyphs,QPainterPath * path,QTextItem::RenderFlags flags)410 void QFontEngineQPF2::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
411 {
412 addBitmapFontToPath(x, y, glyphs, path, flags);
413 }
414
boundingBox(const QGlyphLayout & glyphs)415 glyph_metrics_t QFontEngineQPF2::boundingBox(const QGlyphLayout &glyphs)
416 {
417 glyph_metrics_t overall;
418 // initialize with line height, we get the same behaviour on all platforms
419 overall.y = -ascent();
420 overall.height = ascent() + descent() + 1;
421
422 QFixed ymax = 0;
423 QFixed xmax = 0;
424 for (int i = 0; i < glyphs.numGlyphs; i++) {
425 const Glyph *g = findGlyph(glyphs.glyphs[i]);
426 if (!g)
427 continue;
428
429 QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
430 QFixed y = overall.yoff + glyphs.offsets[i].y + g->y;
431 overall.x = qMin(overall.x, x);
432 overall.y = qMin(overall.y, y);
433 xmax = qMax(xmax, x + g->width);
434 ymax = qMax(ymax, y + g->height);
435 overall.xoff += g->advance;
436 }
437 overall.height = qMax(overall.height, ymax - overall.y);
438 overall.width = xmax - overall.x;
439
440 return overall;
441 }
442
boundingBox(glyph_t glyph)443 glyph_metrics_t QFontEngineQPF2::boundingBox(glyph_t glyph)
444 {
445 glyph_metrics_t overall;
446 const Glyph *g = findGlyph(glyph);
447 if (!g)
448 return overall;
449 overall.x = g->x;
450 overall.y = g->y;
451 overall.width = g->width;
452 overall.height = g->height;
453 overall.xoff = g->advance;
454 return overall;
455 }
456
ascent() const457 QFixed QFontEngineQPF2::ascent() const
458 {
459 return QFixed::fromReal(qvariant_cast<qreal>(extractHeaderField(fontData, Tag_Ascent)));
460 }
461
capHeight() const462 QFixed QFontEngineQPF2::capHeight() const
463 {
464 return calculatedCapHeight();
465 }
466
descent() const467 QFixed QFontEngineQPF2::descent() const
468 {
469 return QFixed::fromReal(qvariant_cast<qreal>(extractHeaderField(fontData, Tag_Descent)));
470 }
471
leading() const472 QFixed QFontEngineQPF2::leading() const
473 {
474 return QFixed::fromReal(qvariant_cast<qreal>(extractHeaderField(fontData, Tag_Leading)));
475 }
476
maxCharWidth() const477 qreal QFontEngineQPF2::maxCharWidth() const
478 {
479 return qvariant_cast<qreal>(extractHeaderField(fontData, Tag_MaxCharWidth));
480 }
481
minLeftBearing() const482 qreal QFontEngineQPF2::minLeftBearing() const
483 {
484 return qvariant_cast<qreal>(extractHeaderField(fontData, Tag_MinLeftBearing));
485 }
486
minRightBearing() const487 qreal QFontEngineQPF2::minRightBearing() const
488 {
489 return qvariant_cast<qreal>(extractHeaderField(fontData, Tag_MinRightBearing));
490 }
491
underlinePosition() const492 QFixed QFontEngineQPF2::underlinePosition() const
493 {
494 return QFixed::fromReal(qvariant_cast<qreal>(extractHeaderField(fontData, Tag_UnderlinePosition)));
495 }
496
lineThickness() const497 QFixed QFontEngineQPF2::lineThickness() const
498 {
499 return QFixed::fromReal(qvariant_cast<qreal>(extractHeaderField(fontData, Tag_LineThickness)));
500 }
501
isValid() const502 bool QFontEngineQPF2::isValid() const
503 {
504 return fontData && dataSize && cmapOffset
505 && glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
506 }
507
generate()508 void QPF2Generator::generate()
509 {
510 writeHeader();
511 writeGMap();
512 writeBlock(QFontEngineQPF2::GlyphBlock, QByteArray());
513
514 dev->seek(4); // position of header.lock
515 writeUInt32(0);
516 }
517
writeHeader()518 void QPF2Generator::writeHeader()
519 {
520 QFontEngineQPF2::Header header;
521
522 header.magic[0] = 'Q';
523 header.magic[1] = 'P';
524 header.magic[2] = 'F';
525 header.magic[3] = '2';
526 header.lock = 1;
527 header.majorVersion = QFontEngineQPF2::CurrentMajorVersion;
528 header.minorVersion = QFontEngineQPF2::CurrentMinorVersion;
529 header.dataSize = 0;
530 dev->write((const char *)&header, sizeof(header));
531
532 writeTaggedString(QFontEngineQPF2::Tag_FontName, fe->fontDef.family.toUtf8());
533
534 QFontEngine::FaceId face = fe->faceId();
535 writeTaggedString(QFontEngineQPF2::Tag_FileName, face.filename);
536 writeTaggedUInt32(QFontEngineQPF2::Tag_FileIndex, face.index);
537
538 {
539 const QByteArray head = fe->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd'));
540 if (head.size() >= 4) {
541 const quint32 revision = qFromBigEndian<quint32>(head.constData());
542 writeTaggedUInt32(QFontEngineQPF2::Tag_FontRevision, revision);
543 }
544 }
545
546 writeTaggedQFixed(QFontEngineQPF2::Tag_Ascent, fe->ascent());
547 writeTaggedQFixed(QFontEngineQPF2::Tag_Descent, fe->descent());
548 writeTaggedQFixed(QFontEngineQPF2::Tag_Leading, fe->leading());
549 writeTaggedQFixed(QFontEngineQPF2::Tag_XHeight, fe->xHeight());
550 writeTaggedQFixed(QFontEngineQPF2::Tag_AverageCharWidth, fe->averageCharWidth());
551 writeTaggedQFixed(QFontEngineQPF2::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth()));
552 writeTaggedQFixed(QFontEngineQPF2::Tag_LineThickness, fe->lineThickness());
553 writeTaggedQFixed(QFontEngineQPF2::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing()));
554 writeTaggedQFixed(QFontEngineQPF2::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing()));
555 writeTaggedQFixed(QFontEngineQPF2::Tag_UnderlinePosition, fe->underlinePosition());
556 writeTaggedUInt8(QFontEngineQPF2::Tag_PixelSize, fe->fontDef.pixelSize);
557 writeTaggedUInt8(QFontEngineQPF2::Tag_Weight, fe->fontDef.weight);
558 writeTaggedUInt8(QFontEngineQPF2::Tag_Style, fe->fontDef.style);
559
560 writeTaggedUInt8(QFontEngineQPF2::Tag_GlyphFormat, QFontEngineQPF2::AlphamapGlyphs);
561
562 writeTaggedString(QFontEngineQPF2::Tag_EndOfHeader, QByteArray());
563 align4();
564
565 const quint64 size = dev->pos();
566 header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
567 dev->seek(0);
568 dev->write((const char *)&header, sizeof(header));
569 dev->seek(size);
570 }
571
writeGMap()572 void QPF2Generator::writeGMap()
573 {
574 const quint16 glyphCount = fe->glyphCount();
575
576 writeUInt16(QFontEngineQPF2::GMapBlock);
577 writeUInt16(0); // padding
578 writeUInt32(glyphCount * 4);
579
580 QByteArray &buffer = dev->buffer();
581 const int numBytes = glyphCount * sizeof(quint32);
582 qint64 pos = buffer.size();
583 buffer.resize(pos + numBytes);
584 memset(buffer.data() + pos, 0xff, numBytes);
585 dev->seek(pos + numBytes);
586 }
587
writeBlock(QFontEngineQPF2::BlockTag tag,const QByteArray & data)588 void QPF2Generator::writeBlock(QFontEngineQPF2::BlockTag tag, const QByteArray &data)
589 {
590 writeUInt16(tag);
591 writeUInt16(0); // padding
592 const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
593 writeUInt32(data.size() + padSize);
594 dev->write(data);
595 for (int i = 0; i < padSize; ++i)
596 writeUInt8(0);
597 }
598
writeTaggedString(QFontEngineQPF2::HeaderTag tag,const QByteArray & string)599 void QPF2Generator::writeTaggedString(QFontEngineQPF2::HeaderTag tag, const QByteArray &string)
600 {
601 writeUInt16(tag);
602 writeUInt16(string.length());
603 dev->write(string);
604 }
605
writeTaggedUInt32(QFontEngineQPF2::HeaderTag tag,quint32 value)606 void QPF2Generator::writeTaggedUInt32(QFontEngineQPF2::HeaderTag tag, quint32 value)
607 {
608 writeUInt16(tag);
609 writeUInt16(sizeof(value));
610 writeUInt32(value);
611 }
612
writeTaggedUInt8(QFontEngineQPF2::HeaderTag tag,quint8 value)613 void QPF2Generator::writeTaggedUInt8(QFontEngineQPF2::HeaderTag tag, quint8 value)
614 {
615 writeUInt16(tag);
616 writeUInt16(sizeof(value));
617 writeUInt8(value);
618 }
619
writeTaggedQFixed(QFontEngineQPF2::HeaderTag tag,QFixed value)620 void QPF2Generator::writeTaggedQFixed(QFontEngineQPF2::HeaderTag tag, QFixed value)
621 {
622 writeUInt16(tag);
623 writeUInt16(sizeof(quint32));
624 writeUInt32(value.value());
625 }
626
627 QT_END_NAMESPACE
628