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
53QT_BEGIN_NAMESPACE
54
55//#define DEBUG_HEADER
56//#define DEBUG_FONTENGINE
57
58static 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
98template <typename T>
99T 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
118static 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
151const 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>(source: 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
169bool 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>(source: 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, endPtr: tagEndPtr);
188 VERIFY(tagPtr);
189 }
190
191 VERIFY(tagPtr <= tagEndPtr);
192 return true;
193}
194
195QVariant 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>(source: header->dataSize);
200 while (tagPtr < endPtr - 3) {
201 quint16 tag = readValue<quint16>(data&: tagPtr);
202 quint16 length = readValue<quint16>(data&: tagPtr);
203 if (tag == requestedTag) {
204 switch (tagTypes[requestedTag]) {
205 case StringType:
206 return QVariant(QString::fromUtf8(str: reinterpret_cast<const char *>(tagPtr), size: length));
207 case UInt32Type:
208 return QVariant(readValue<quint32>(data&: tagPtr));
209 case UInt8Type:
210 return QVariant(uint(*tagPtr));
211 case FixedType:
212 return QVariant(QFixed::fromFixed(fixed: readValue<quint32>(data&: 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
227QFontEngineQPF2::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(data: fontData, size: 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>(source: header->dataSize);
259 const uchar *endPtr = fontData + dataSize;
260 while (imgData <= endPtr - 8) {
261 quint16 blockTag = readValue<quint16>(data&: imgData);
262 imgData += 2; // skip padding
263 quint32 blockSize = readValue<quint32>(data&: 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(fileName: extractHeaderField(data: fontData, requestedTag: Tag_FileName).toString());
280 face_id.index = extractHeaderField(data: fontData, requestedTag: Tag_FileIndex).toInt();
281
282 // get the real cmap
283 if (cmapOffset) {
284 cmap = QFontEngine::getCMap(table: fontData + cmapOffset, tableSize: cmapSize, isSymbolFont: &symbol, cmapSize: &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>(source: 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
313QFontEngineQPF2::~QFontEngineQPF2()
314{
315}
316
317bool 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(dest: buffer, src: cmap, n: cmapSize);
324 *length = cmapSize;
325 Q_ASSERT(int(*length) > 0);
326 return true;
327}
328
329glyph_t QFontEngineQPF2::glyphIndex(uint ucs4) const
330{
331 glyph_t glyph = getTrueTypeGlyphIndex(cmap, cmapSize, unicode: ucs4);
332 if (glyph == 0 && symbol && ucs4 < 0x100)
333 glyph = getTrueTypeGlyphIndex(cmap, cmapSize, unicode: ucs4 + 0xf000);
334 if (!findGlyph(g: glyph))
335 glyph = 0;
336
337 return glyph;
338}
339
340bool 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, unicode: uc);
358 if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
359 glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, unicode: 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, unicode: 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
387void QFontEngineQPF2::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
388{
389 for (int i = 0; i < glyphs->numGlyphs; ++i) {
390 const Glyph *g = findGlyph(g: glyphs->glyphs[i]);
391 if (!g)
392 continue;
393 glyphs->advances[i] = g->advance;
394 }
395}
396
397QImage 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
410void QFontEngineQPF2::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
411{
412 addBitmapFontToPath(x, y, glyphs, path, flags);
413}
414
415glyph_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(g: 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(a: overall.x, b: x);
432 overall.y = qMin(a: overall.y, b: y);
433 xmax = qMax(a: xmax, b: x + g->width);
434 ymax = qMax(a: ymax, b: y + g->height);
435 overall.xoff += g->advance;
436 }
437 overall.height = qMax(a: overall.height, b: ymax - overall.y);
438 overall.width = xmax - overall.x;
439
440 return overall;
441}
442
443glyph_metrics_t QFontEngineQPF2::boundingBox(glyph_t glyph)
444{
445 glyph_metrics_t overall;
446 const Glyph *g = findGlyph(g: 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
457QFixed QFontEngineQPF2::ascent() const
458{
459 return QFixed::fromReal(r: qvariant_cast<qreal>(v: extractHeaderField(data: fontData, requestedTag: Tag_Ascent)));
460}
461
462QFixed QFontEngineQPF2::capHeight() const
463{
464 return calculatedCapHeight();
465}
466
467QFixed QFontEngineQPF2::descent() const
468{
469 return QFixed::fromReal(r: qvariant_cast<qreal>(v: extractHeaderField(data: fontData, requestedTag: Tag_Descent)));
470}
471
472QFixed QFontEngineQPF2::leading() const
473{
474 return QFixed::fromReal(r: qvariant_cast<qreal>(v: extractHeaderField(data: fontData, requestedTag: Tag_Leading)));
475}
476
477qreal QFontEngineQPF2::maxCharWidth() const
478{
479 return qvariant_cast<qreal>(v: extractHeaderField(data: fontData, requestedTag: Tag_MaxCharWidth));
480}
481
482qreal QFontEngineQPF2::minLeftBearing() const
483{
484 return qvariant_cast<qreal>(v: extractHeaderField(data: fontData, requestedTag: Tag_MinLeftBearing));
485}
486
487qreal QFontEngineQPF2::minRightBearing() const
488{
489 return qvariant_cast<qreal>(v: extractHeaderField(data: fontData, requestedTag: Tag_MinRightBearing));
490}
491
492QFixed QFontEngineQPF2::underlinePosition() const
493{
494 return QFixed::fromReal(r: qvariant_cast<qreal>(v: extractHeaderField(data: fontData, requestedTag: Tag_UnderlinePosition)));
495}
496
497QFixed QFontEngineQPF2::lineThickness() const
498{
499 return QFixed::fromReal(r: qvariant_cast<qreal>(v: extractHeaderField(data: fontData, requestedTag: Tag_LineThickness)));
500}
501
502bool QFontEngineQPF2::isValid() const
503{
504 return fontData && dataSize && cmapOffset
505 && glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
506}
507
508void QPF2Generator::generate()
509{
510 writeHeader();
511 writeGMap();
512 writeBlock(tag: QFontEngineQPF2::GlyphBlock, data: QByteArray());
513
514 dev->seek(off: 4); // position of header.lock
515 writeUInt32(value: 0);
516}
517
518void 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(data: (const char *)&header, len: sizeof(header));
531
532 writeTaggedString(tag: QFontEngineQPF2::Tag_FontName, string: fe->fontDef.family.toUtf8());
533
534 QFontEngine::FaceId face = fe->faceId();
535 writeTaggedString(tag: QFontEngineQPF2::Tag_FileName, string: face.filename);
536 writeTaggedUInt32(tag: QFontEngineQPF2::Tag_FileIndex, value: 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>(src: head.constData());
542 writeTaggedUInt32(tag: QFontEngineQPF2::Tag_FontRevision, value: revision);
543 }
544 }
545
546 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_Ascent, value: fe->ascent());
547 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_Descent, value: fe->descent());
548 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_Leading, value: fe->leading());
549 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_XHeight, value: fe->xHeight());
550 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_AverageCharWidth, value: fe->averageCharWidth());
551 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_MaxCharWidth, value: QFixed::fromReal(r: fe->maxCharWidth()));
552 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_LineThickness, value: fe->lineThickness());
553 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_MinLeftBearing, value: QFixed::fromReal(r: fe->minLeftBearing()));
554 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_MinRightBearing, value: QFixed::fromReal(r: fe->minRightBearing()));
555 writeTaggedQFixed(tag: QFontEngineQPF2::Tag_UnderlinePosition, value: fe->underlinePosition());
556 writeTaggedUInt8(tag: QFontEngineQPF2::Tag_PixelSize, value: fe->fontDef.pixelSize);
557 writeTaggedUInt8(tag: QFontEngineQPF2::Tag_Weight, value: fe->fontDef.weight);
558 writeTaggedUInt8(tag: QFontEngineQPF2::Tag_Style, value: fe->fontDef.style);
559
560 writeTaggedUInt8(tag: QFontEngineQPF2::Tag_GlyphFormat, value: QFontEngineQPF2::AlphamapGlyphs);
561
562 writeTaggedString(tag: QFontEngineQPF2::Tag_EndOfHeader, string: QByteArray());
563 align4();
564
565 const quint64 size = dev->pos();
566 header.dataSize = qToBigEndian<quint16>(source: size - sizeof(header));
567 dev->seek(off: 0);
568 dev->write(data: (const char *)&header, len: sizeof(header));
569 dev->seek(off: size);
570}
571
572void QPF2Generator::writeGMap()
573{
574 const quint16 glyphCount = fe->glyphCount();
575
576 writeUInt16(value: QFontEngineQPF2::GMapBlock);
577 writeUInt16(value: 0); // padding
578 writeUInt32(value: glyphCount * 4);
579
580 QByteArray &buffer = dev->buffer();
581 const int numBytes = glyphCount * sizeof(quint32);
582 qint64 pos = buffer.size();
583 buffer.resize(size: pos + numBytes);
584 memset(s: buffer.data() + pos, c: 0xff, n: numBytes);
585 dev->seek(off: pos + numBytes);
586}
587
588void QPF2Generator::writeBlock(QFontEngineQPF2::BlockTag tag, const QByteArray &data)
589{
590 writeUInt16(value: tag);
591 writeUInt16(value: 0); // padding
592 const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
593 writeUInt32(value: data.size() + padSize);
594 dev->write(data);
595 for (int i = 0; i < padSize; ++i)
596 writeUInt8(value: 0);
597}
598
599void QPF2Generator::writeTaggedString(QFontEngineQPF2::HeaderTag tag, const QByteArray &string)
600{
601 writeUInt16(value: tag);
602 writeUInt16(value: string.length());
603 dev->write(data: string);
604}
605
606void QPF2Generator::writeTaggedUInt32(QFontEngineQPF2::HeaderTag tag, quint32 value)
607{
608 writeUInt16(value: tag);
609 writeUInt16(value: sizeof(value));
610 writeUInt32(value);
611}
612
613void QPF2Generator::writeTaggedUInt8(QFontEngineQPF2::HeaderTag tag, quint8 value)
614{
615 writeUInt16(value: tag);
616 writeUInt16(value: sizeof(value));
617 writeUInt8(value);
618}
619
620void QPF2Generator::writeTaggedQFixed(QFontEngineQPF2::HeaderTag tag, QFixed value)
621{
622 writeUInt16(value: tag);
623 writeUInt16(value: sizeof(quint32));
624 writeUInt32(value: value.value());
625}
626
627QT_END_NAMESPACE
628

source code of qtbase/src/gui/text/qfontengine_qpf2.cpp