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 "qfontsubset_p.h"
41 #include <qdebug.h>
42 #include <qendian.h>
43 #include <qpainterpath.h>
44 #include "private/qpdf_p.h"
45 
46 #include "qfontsubset_agl.cpp"
47 
48 #include <algorithm>
49 
50 QT_BEGIN_NAMESPACE
51 
52 #ifndef QT_NO_PDF
53 
54 // This map is used for symbol fonts to get the correct glyph names for the latin range
55 static const unsigned short symbol_map[0x100] = {
56     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
57     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
58     0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
59     0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
60     0x0020, 0x0021, 0x2200, 0x0023, 0x2203, 0x0025, 0x0026, 0x220b,
61     0x0028, 0x0029, 0x2217, 0x002b, 0x002c, 0x2212, 0x002e, 0x002f,
62     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
63     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
64 
65     0x2245, 0x0391, 0x0392, 0x03a7, 0x0394, 0x0395, 0x03a6, 0x0393,
66     0x0397, 0x0399, 0x03d1, 0x039a, 0x039b, 0x039c, 0x039d, 0x039f,
67     0x03a0, 0x0398, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03c2, 0x03a9,
68     0x039e, 0x03a8, 0x0396, 0x005b, 0x2234, 0x005d, 0x22a5, 0x005f,
69     0xf8e5, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3,
70     0x03b7, 0x03b9, 0x03d5, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03bf,
71     0x03c0, 0x03b8, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03d6, 0x03c9,
72     0x03be, 0x03c8, 0x03b6, 0x007b, 0x007c, 0x007d, 0x223c, 0x007f,
73 
74     0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
75     0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
76     0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
77     0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
78     0x20ac, 0x03d2, 0x2023, 0x2264, 0x2044, 0x221e, 0x0192, 0x2263,
79     0x2666, 0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193,
80     0x00b0, 0x00b1, 0x2033, 0x2265, 0x00d7, 0x221d, 0x2202, 0x2022,
81     0x00f7, 0x2260, 0x2261, 0x2248, 0x2026, 0xf8e6, 0xf8e7, 0x21b5,
82 
83     0x2135, 0x2111, 0x211c, 0x2118, 0x2297, 0x2295, 0x2205, 0x2229,
84     0x222a, 0x2283, 0x2287, 0x2284, 0x2282, 0x2286, 0x2208, 0x2209,
85     0x2220, 0x2207, 0xf6da, 0xf6d9, 0xf6db, 0x220f, 0x221a, 0x22c5,
86     0x00ac, 0x2227, 0x2228, 0x21d4, 0x21d0, 0x21d1, 0x21d2, 0x21d3,
87     0x25ca, 0x2329, 0xf8e8, 0xf8e9, 0xf8ea, 0x2211, 0xf8eb, 0xf8ec,
88     0xf8ed, 0xf8ee, 0xf8ef, 0xf8f0, 0xf8f1, 0xf8f2, 0xf8f3, 0xf8f4,
89     0x0000, 0x232a, 0x222b, 0x2320, 0xf8f5, 0x2321, 0xf8f6, 0xf8f7,
90     0xf8f8, 0xf8f9, 0xf8fa, 0xf8fb, 0xf8fc, 0xf8fd, 0xf8fe, 0x0000
91 };
92 
93 // ---------------------------- PS/PDF helper methods -----------------------------------
94 
95 
96 
glyphName(unsigned short unicode,bool symbol)97 QByteArray QFontSubset::glyphName(unsigned short unicode, bool symbol)
98 {
99     if (symbol && unicode < 0x100)
100         // map from latin1 to symbol
101         unicode = symbol_map[unicode];
102 
103     const AGLEntry *r = std::lower_bound(unicode_to_agl_map, unicode_to_agl_map + unicode_to_agl_map_size, unicode);
104     if ((r != unicode_to_agl_map + unicode_to_agl_map_size) && !(unicode < *r))
105         return glyph_names + r->index;
106 
107     char buffer[8];
108     buffer[0] = 'u';
109     buffer[1] = 'n';
110     buffer[2] = 'i';
111     QPdf::toHex(unicode, buffer+3);
112     return buffer;
113 }
114 
glyphName(unsigned int glyph,const QVector<int> & reverseMap) const115 QByteArray QFontSubset::glyphName(unsigned int glyph, const QVector<int> &reverseMap) const
116 {
117     uint glyphIndex = glyph_indices[glyph];
118 
119     if (glyphIndex == 0)
120         return "/.notdef";
121 
122     QByteArray ba;
123     QPdf::ByteStream s(&ba);
124     if (reverseMap[glyphIndex] && reverseMap[glyphIndex] < 0x10000) {
125         s << '/' << glyphName(reverseMap[glyphIndex], false);
126     } else {
127         s << "/gl" << (int)glyphIndex;
128     }
129     return ba;
130 }
131 
132 
widthArray() const133 QByteArray QFontSubset::widthArray() const
134 {
135     Q_ASSERT(!widths.isEmpty());
136 
137     QFontEngine::Properties properties = fontEngine->properties();
138 
139     QByteArray width;
140     QPdf::ByteStream s(&width);
141     const qreal scale = 1000.0/emSquare.toInt();
142 
143     QFixed defWidth = widths[0];
144     //qDebug("defWidth=%d, scale=%f", defWidth.toInt(), scale.toReal());
145     for (int i = 0; i < nGlyphs(); ++i) {
146         if (defWidth != widths[i])
147             defWidth = 0;
148     }
149     if (defWidth > 0) {
150         s << "/DW " << qRound(defWidth.toInt() * scale);
151     } else {
152         s << "/W [";
153         for (int g = 0; g < nGlyphs();) {
154             QFixed w = widths[g];
155             int start = g;
156             int startLinear = 0;
157             ++g;
158             while (g < nGlyphs()) {
159                 QFixed nw = widths[g];
160                 if (nw == w) {
161                 if (!startLinear)
162                     startLinear = g - 1;
163                 } else {
164                     if (startLinear > 0 && g - startLinear >= 10)
165                         break;
166                     startLinear = 0;
167                 }
168                 w = nw;
169                 ++g;
170             }
171             // qDebug("start=%x startLinear=%x g-1=%x",start,startLinear,g-1);
172             if (g - startLinear < 10)
173                 startLinear = 0;
174             int endnonlinear = startLinear ? startLinear : g;
175             // qDebug("    startLinear=%x endnonlinear=%x", startLinear,endnonlinear);
176             if (endnonlinear > start) {
177                 s << start << '[';
178                 for (int i = start; i < endnonlinear; ++i)
179                     s << qRound(widths[i].toInt() * scale);
180                 s << "]\n";
181             }
182             if (startLinear)
183                 s << startLinear << g - 1 << qRound(widths[startLinear].toInt() * scale) << '\n';
184         }
185         s << "]\n";
186     }
187     return width;
188 }
189 
checkRanges(QPdf::ByteStream & ts,QByteArray & ranges,int & nranges)190 static void checkRanges(QPdf::ByteStream &ts, QByteArray &ranges, int &nranges)
191 {
192     if (++nranges > 100) {
193         ts << nranges << "beginbfrange\n"
194            << ranges << "endbfrange\n";
195         ranges = QByteArray();
196         nranges = 0;
197     }
198 }
199 
getReverseMap() const200 QVector<int> QFontSubset::getReverseMap() const
201 {
202     QVector<int> reverseMap(0x10000, 0);
203     for (uint uc = 0; uc < 0x10000; ++uc) {
204         int idx = glyph_indices.indexOf(fontEngine->glyphIndex(uc));
205         if (idx >= 0 && !reverseMap.at(idx))
206             reverseMap[idx] = uc;
207     }
208     return reverseMap;
209 }
210 
createToUnicodeMap() const211 QByteArray QFontSubset::createToUnicodeMap() const
212 {
213     QVector<int> reverseMap = getReverseMap();
214 
215     QByteArray touc;
216     QPdf::ByteStream ts(&touc);
217     ts << "/CIDInit /ProcSet findresource begin\n"
218         "12 dict begin\n"
219         "begincmap\n"
220         "/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def\n"
221         "/CMapName /Adobe-Identity-UCS def\n"
222         "/CMapType 2 def\n"
223         "1 begincodespacerange\n"
224         "<0000> <FFFF>\n"
225         "endcodespacerange\n";
226 
227     int nranges = 1;
228     QByteArray ranges = "<0000> <0000> <0000>\n";
229     QPdf::ByteStream s(&ranges);
230 
231     char buf[5];
232     for (int g = 1; g < nGlyphs(); ) {
233         int uc0 = reverseMap.at(g);
234         if (!uc0) {
235             ++g;
236             continue;
237         }
238         int start = g;
239         int startLinear = 0;
240         ++g;
241         while (g < nGlyphs()) {
242             int uc = reverseMap[g];
243             // cmaps can't have the high byte changing within one range, so we need to break on that as well
244             if (!uc || (g>>8) != (start >> 8))
245                 break;
246             if (uc == uc0 + 1) {
247                 if (!startLinear)
248                     startLinear = g - 1;
249             } else {
250                 if (startLinear > 0 && g - startLinear >= 10)
251                     break;
252                 startLinear = 0;
253             }
254             uc0 = uc;
255             ++g;
256         }
257         // qDebug("start=%x startLinear=%x g-1=%x",start,startLinear,g-1);
258         if (g - startLinear < 10)
259             startLinear = 0;
260         int endnonlinear = startLinear ? startLinear : g;
261         // qDebug("    startLinear=%x endnonlinear=%x", startLinear,endnonlinear);
262         if (endnonlinear > start) {
263             s << '<' << QPdf::toHex((ushort)start, buf) << "> <";
264             s << QPdf::toHex((ushort)(endnonlinear - 1), buf) << "> ";
265             if (endnonlinear == start + 1) {
266                 s << '<' << QPdf::toHex((ushort)reverseMap[start], buf) << ">\n";
267             } else {
268                 s << '[';
269                 for (int i = start; i < endnonlinear; ++i) {
270                     s << '<' << QPdf::toHex((ushort)reverseMap[i], buf) << "> ";
271                 }
272                 s << "]\n";
273             }
274             checkRanges(ts, ranges, nranges);
275         }
276         if (startLinear) {
277             while (startLinear < g) {
278                 int len = g - startLinear;
279                 int uc_start = reverseMap[startLinear];
280                 int uc_end = uc_start + len - 1;
281                 if ((uc_end >> 8) != (uc_start >> 8))
282                     len = 256 - (uc_start & 0xff);
283                 s << '<' << QPdf::toHex((ushort)startLinear, buf) << "> <";
284                 s << QPdf::toHex((ushort)(startLinear + len - 1), buf) << "> ";
285                 s << '<' << QPdf::toHex((ushort)reverseMap[startLinear], buf) << ">\n";
286                 checkRanges(ts, ranges, nranges);
287                 startLinear += len;
288             }
289         }
290     }
291     if (nranges) {
292         ts << nranges << "beginbfrange\n"
293            << ranges << "endbfrange\n";
294     }
295     ts << "endcmap\n"
296         "CMapName currentdict /CMap defineresource pop\n"
297         "end\n"
298         "end\n";
299 
300     return touc;
301 }
302 
addGlyph(int index)303 int QFontSubset::addGlyph(int index)
304 {
305     int idx = glyph_indices.indexOf(index);
306     if (idx < 0) {
307         idx = glyph_indices.size();
308         glyph_indices.append(index);
309     }
310     return idx;
311 }
312 
313 #endif // QT_NO_PDF
314 
315 // ------------------------------ Truetype generation ----------------------------------------------
316 
317 typedef qint16 F2DOT14;
318 typedef quint32 Tag;
319 typedef quint16 GlyphID;
320 typedef quint16 Offset;
321 
322 
323 class QTtfStream {
324 public:
QTtfStream(QByteArray & ba)325     QTtfStream(QByteArray &ba) : data((uchar *)ba.data()) { start = data; }
operator <<(quint8 v)326     QTtfStream &operator <<(quint8 v) { *data = v; ++data; return *this; }
operator <<(quint16 v)327     QTtfStream &operator <<(quint16 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
operator <<(quint32 v)328     QTtfStream &operator <<(quint32 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
operator <<(qint8 v)329     QTtfStream &operator <<(qint8 v) { *data = quint8(v); ++data; return *this; }
operator <<(qint16 v)330     QTtfStream &operator <<(qint16 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
operator <<(qint32 v)331     QTtfStream &operator <<(qint32 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
operator <<(qint64 v)332     QTtfStream &operator <<(qint64 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
333 
offset() const334     int offset() const { return data - start; }
setOffset(int o)335     void setOffset(int o) { data = start + o; }
align4()336     void align4() { while (offset() & 3) { *data = '\0'; ++data; } }
337 private:
338     uchar *data;
339     uchar *start;
340 };
341 
342 struct QTtfTable {
343     Tag tag;
344     QByteArray data;
345 };
346 Q_DECLARE_TYPEINFO(QTtfTable, Q_MOVABLE_TYPE);
347 
348 
349 struct qttf_head_table {
350     qint32 font_revision;
351     quint16 flags;
352     qint64 created;
353     qint64 modified;
354     qint16 xMin;
355     qint16 yMin;
356     qint16 xMax;
357     qint16 yMax;
358     quint16 macStyle;
359     qint16 indexToLocFormat;
360 };
361 Q_DECLARE_TYPEINFO(qttf_head_table, Q_PRIMITIVE_TYPE);
362 
363 
364 struct qttf_hhea_table {
365     qint16 ascender;
366     qint16 descender;
367     qint16 lineGap;
368     quint16 maxAdvanceWidth;
369     qint16 minLeftSideBearing;
370     qint16 minRightSideBearing;
371     qint16 xMaxExtent;
372     quint16 numberOfHMetrics;
373 };
374 Q_DECLARE_TYPEINFO(qttf_hhea_table, Q_PRIMITIVE_TYPE);
375 
376 
377 struct qttf_maxp_table {
378     quint16 numGlyphs;
379     quint16 maxPoints;
380     quint16 maxContours;
381     quint16 maxCompositePoints;
382     quint16 maxCompositeContours;
383     quint16 maxComponentElements;
384     quint16 maxComponentDepth;
385 };
386 Q_DECLARE_TYPEINFO(qttf_maxp_table, Q_PRIMITIVE_TYPE);
387 
388 struct qttf_name_table {
389     QString copyright;
390     QString family;
391     QString subfamily;
392     QString postscript_name;
393 };
394 Q_DECLARE_TYPEINFO(qttf_name_table, Q_MOVABLE_TYPE);
395 
396 
397 static QTtfTable generateHead(const qttf_head_table &head);
398 static QTtfTable generateHhea(const qttf_hhea_table &hhea);
399 static QTtfTable generateMaxp(const qttf_maxp_table &maxp);
400 static QTtfTable generateName(const qttf_name_table &name);
401 
402 struct qttf_font_tables
403 {
404     qttf_head_table head;
405     qttf_hhea_table hhea;
406     qttf_maxp_table maxp;
407 };
408 
409 
410 struct QTtfGlyph {
411     quint16 index;
412     qint16 xMin;
413     qint16 xMax;
414     qint16 yMin;
415     qint16 yMax;
416     quint16 advanceWidth;
417     qint16 lsb;
418     quint16 numContours;
419     quint16 numPoints;
420     QByteArray data;
421 };
422 Q_DECLARE_TYPEINFO(QTtfGlyph, Q_MOVABLE_TYPE);
423 
424 static QTtfGlyph generateGlyph(int index, const QPainterPath &path, qreal advance, qreal lsb, qreal ppem);
425 // generates glyf, loca and hmtx
426 static QVector<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QVector<QTtfGlyph> &_glyphs);
427 
428 static QByteArray bindFont(const QVector<QTtfTable>& _tables);
429 
430 
checksum(const QByteArray & table)431 static quint32 checksum(const QByteArray &table)
432 {
433     quint32 sum = 0;
434     int offset = 0;
435     const uchar *d = (const uchar *)table.constData();
436     while (offset <= table.size()-3) {
437         sum += qFromBigEndian<quint32>(d + offset);
438         offset += 4;
439     }
440     int shift = 24;
441     quint32 x = 0;
442     while (offset < table.size()) {
443         x |= ((quint32)d[offset]) << shift;
444         ++offset;
445         shift -= 8;
446     }
447     sum += x;
448 
449     return sum;
450 }
451 
generateHead(const qttf_head_table & head)452 static QTtfTable generateHead(const qttf_head_table &head)
453 {
454     const int head_size = 54;
455     QTtfTable t;
456     t.tag = MAKE_TAG('h', 'e', 'a', 'd');
457     t.data.resize(head_size);
458 
459     QTtfStream s(t.data);
460 
461 // qint32  Table version number  0x00010000 for version 1.0.
462 // qint32  fontRevision  Set by font manufacturer.
463     s << qint32(0x00010000)
464       << head.font_revision
465 // quint32  checkSumAdjustment  To compute: set it to 0, sum the entire font as quint32, then store 0xB1B0AFBA - sum.
466       << quint32(0)
467 // quint32  magicNumber  Set to 0x5F0F3CF5.
468       << quint32(0x5F0F3CF5)
469 // quint16  flags  Bit 0: Baseline for font at y=0;
470 // Bit 1: Left sidebearing point at x=0;
471 // Bit 2: Instructions may depend on point size;
472 // Bit 3: Force ppem to integer values for all internal scaler math; may use fractional ppem sizes if this bit is clear;
473 // Bit 4: Instructions may alter advance width (the advance widths might not scale linearly);
474 // Bits 5-10: These should be set according to  Apple's specification . However, they are not implemented in OpenType.
475 // Bit 11: Font data is 'lossless,' as a result of having been compressed and decompressed with the Agfa MicroType Express engine.
476 // Bit 12: Font converted (produce compatible metrics)
477 // Bit 13: Font optimized for ClearType
478 // Bit 14: Reserved, set to 0
479 // Bit 15: Reserved, set to 0
480       << quint16(0)
481 
482 // quint16  unitsPerEm  Valid range is from 16 to 16384. This value should be a power of 2 for fonts that have TrueType outlines.
483       << quint16(2048)
484 // qint64  created  Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer
485       << head.created
486 // qint64  modified  Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer
487       << head.modified
488 // qint16  xMin  For all glyph bounding boxes.
489 // qint16  yMin  For all glyph bounding boxes.
490 // qint16  xMax  For all glyph bounding boxes.
491 // qint16  yMax  For all glyph bounding boxes.
492       << head.xMin
493       << head.yMin
494       << head.xMax
495       << head.yMax
496 // quint16  macStyle  Bit 0: Bold (if set to 1);
497 // Bit 1: Italic (if set to 1)
498 // Bit 2: Underline (if set to 1)
499 // Bit 3: Outline (if set to 1)
500 // Bit 4: Shadow (if set to 1)
501 // Bit 5: Condensed (if set to 1)
502 // Bit 6: Extended (if set to 1)
503 // Bits 7-15: Reserved (set to 0).
504       << head.macStyle
505 // quint16  lowestRecPPEM  Smallest readable size in pixels.
506       << quint16(6) // just a wild guess
507 // qint16  fontDirectionHint   0: Fully mixed directional glyphs;
508       << qint16(0)
509 // 1: Only strongly left to right;
510 // 2: Like 1 but also contains neutrals;
511 // -1: Only strongly right to left;
512 // -2: Like -1 but also contains neutrals. 1
513 // qint16  indexToLocFormat  0 for short offsets, 1 for long.
514       << head.indexToLocFormat
515 // qint16  glyphDataFormat  0 for current format.
516       << qint16(0);
517 
518     Q_ASSERT(s.offset() == head_size);
519     return t;
520 }
521 
522 
generateHhea(const qttf_hhea_table & hhea)523 static QTtfTable generateHhea(const qttf_hhea_table &hhea)
524 {
525     const int hhea_size = 36;
526     QTtfTable t;
527     t.tag = MAKE_TAG('h', 'h', 'e', 'a');
528     t.data.resize(hhea_size);
529 
530     QTtfStream s(t.data);
531 // qint32  Table version number  0x00010000 for version 1.0.
532     s << qint32(0x00010000)
533 // qint16  Ascender  Typographic ascent.  (Distance from baseline of highest ascender)
534       << hhea.ascender
535 // qint16  Descender  Typographic descent.  (Distance from baseline of lowest descender)
536       << hhea.descender
537 // qint16  LineGap  Typographic line gap.
538 // Negative LineGap values are treated as zero
539 // in Windows 3.1, System 6, and
540 // System 7.
541       << hhea.lineGap
542 // quint16  advanceWidthMax  Maximum advance width value in 'hmtx' table.
543       << hhea.maxAdvanceWidth
544 // qint16  minLeftSideBearing  Minimum left sidebearing value in 'hmtx' table.
545       << hhea.minLeftSideBearing
546 // qint16  minRightSideBearing  Minimum right sidebearing value; calculated as Min(aw - lsb - (xMax - xMin)).
547       << hhea.minRightSideBearing
548 // qint16  xMaxExtent  Max(lsb + (xMax - xMin)).
549       << hhea.xMaxExtent
550 // qint16  caretSlopeRise  Used to calculate the slope of the cursor (rise/run); 1 for vertical.
551       << qint16(1)
552 // qint16  caretSlopeRun  0 for vertical.
553       << qint16(0)
554 // qint16  caretOffset  The amount by which a slanted highlight on a glyph needs to be shifted to produce the best appearance. Set to 0 for non-slanted fonts
555       << qint16(0)
556 // qint16  (reserved)  set to 0
557       << qint16(0)
558 // qint16  (reserved)  set to 0
559       << qint16(0)
560 // qint16  (reserved)  set to 0
561       << qint16(0)
562 // qint16  (reserved)  set to 0
563       << qint16(0)
564 // qint16  metricDataFormat  0 for current format.
565       << qint16(0)
566 // quint16  numberOfHMetrics  Number of hMetric entries in 'hmtx' table
567       << hhea.numberOfHMetrics;
568 
569     Q_ASSERT(s.offset() == hhea_size);
570     return t;
571 }
572 
573 
generateMaxp(const qttf_maxp_table & maxp)574 static QTtfTable generateMaxp(const qttf_maxp_table &maxp)
575 {
576     const int maxp_size = 32;
577     QTtfTable t;
578     t.tag = MAKE_TAG('m', 'a', 'x', 'p');
579     t.data.resize(maxp_size);
580 
581     QTtfStream s(t.data);
582 
583 // qint32  Table version number  0x00010000 for version 1.0.
584     s << qint32(0x00010000)
585 // quint16  numGlyphs  The number of glyphs in the font.
586       << maxp.numGlyphs
587 // quint16  maxPoints  Maximum points in a non-composite glyph.
588       << maxp.maxPoints
589 // quint16  maxContours  Maximum contours in a non-composite glyph.
590       << maxp.maxContours
591 // quint16  maxCompositePoints  Maximum points in a composite glyph.
592       << maxp.maxCompositePoints
593 // quint16  maxCompositeContours  Maximum contours in a composite glyph.
594       << maxp.maxCompositeContours
595 // quint16  maxZones  1 if instructions do not use the twilight zone (Z0), or 2 if instructions do use Z0; should be set to 2 in most cases.
596       << quint16(1) // we do not embed instructions
597 // quint16  maxTwilightPoints  Maximum points used in Z0.
598       << quint16(0)
599 // quint16  maxStorage  Number of Storage Area locations.
600       << quint16(0)
601 // quint16  maxFunctionDefs  Number of FDEFs.
602       << quint16(0)
603 // quint16  maxInstructionDefs  Number of IDEFs.
604       << quint16(0)
605 // quint16  maxStackElements  Maximum stack depth2.
606       << quint16(0)
607 // quint16  maxSizeOfInstructions  Maximum byte count for glyph instructions.
608       << quint16(0)
609 // quint16  maxComponentElements  Maximum number of components referenced at "top level" for any composite glyph.
610       << maxp.maxComponentElements
611 // quint16  maxComponentDepth  Maximum levels of recursion; 1 for simple components.
612       << maxp.maxComponentDepth;
613 
614     Q_ASSERT(s.offset() == maxp_size);
615     return t;
616 }
617 
618 struct QTtfNameRecord {
619     quint16 nameId;
620     QString value;
621 };
622 Q_DECLARE_TYPEINFO(QTtfNameRecord, Q_MOVABLE_TYPE);
623 
624 static QTtfTable generateName(const QVector<QTtfNameRecord> &name);
625 
generateName(const qttf_name_table & name)626 static QTtfTable generateName(const qttf_name_table &name)
627 {
628     QVector<QTtfNameRecord> list;
629     list.reserve(5);
630     QTtfNameRecord rec;
631     rec.nameId = 0;
632     rec.value = name.copyright;
633     list.append(rec);
634     rec.nameId = 1;
635     rec.value = name.family;
636     list.append(rec);
637     rec.nameId = 2;
638     rec.value = name.subfamily;
639     list.append(rec);
640     rec.nameId = 4;
641     rec.value = name.family;
642     if (name.subfamily != QLatin1String("Regular"))
643         rec.value += QLatin1Char(' ') + name.subfamily;
644     list.append(rec);
645     rec.nameId = 6;
646     rec.value = name.postscript_name;
647     list.append(rec);
648 
649     return generateName(list);
650 }
651 
652 // ####### should probably generate Macintosh/Roman name entries as well
generateName(const QVector<QTtfNameRecord> & name)653 static QTtfTable generateName(const QVector<QTtfNameRecord> &name)
654 {
655     const int char_size = 2;
656 
657     QTtfTable t;
658     t.tag = MAKE_TAG('n', 'a', 'm', 'e');
659 
660     const int name_size = 6 + 12*name.size();
661     int string_size = 0;
662     for (int i = 0; i < name.size(); ++i) {
663         string_size += name.at(i).value.length()*char_size;
664     }
665     t.data.resize(name_size + string_size);
666 
667     QTtfStream s(t.data);
668 // quint16  format  Format selector (=0).
669     s << quint16(0)
670 // quint16  count  Number of name records.
671       << quint16(name.size())
672 // quint16  stringOffset  Offset to start of string storage (from start of table).
673       << quint16(name_size);
674 // NameRecord  nameRecord[count]  The name records where count is the number of records.
675 // (Variable)
676 
677     int off = 0;
678     for (int i = 0; i < name.size(); ++i) {
679         int len = name.at(i).value.length()*char_size;
680 // quint16  platformID  Platform ID.
681 // quint16  encodingID  Platform-specific encoding ID.
682 // quint16  languageID  Language ID.
683         s << quint16(3)
684           << quint16(1)
685           << quint16(0x0409) // en_US
686 // quint16  nameId  Name ID.
687           << name.at(i).nameId
688 // quint16  length  String length (in bytes).
689           << quint16(len)
690 // quint16  offset  String offset from start of storage area (in bytes).
691           << quint16(off);
692         off += len;
693     }
694     for (int i = 0; i < name.size(); ++i) {
695         const QString &n = name.at(i).value;
696         const ushort *uc = n.utf16();
697         for (int i = 0; i < n.length(); ++i) {
698             s << quint16(*uc);
699             ++uc;
700         }
701     }
702     return t;
703 }
704 
705 
706 enum Flags {
707     OffCurve = 0,
708     OnCurve = (1 << 0),
709     XShortVector = (1 << 1),
710     YShortVector = (1 << 2),
711     Repeat = (1 << 3),
712     XSame = (1 << 4),
713     XShortPositive = (1 << 4),
714     YSame = (1 << 5),
715     YShortPositive = (1 << 5)
716 };
717 struct TTF_POINT {
718     qint16 x;
719     qint16 y;
720     quint8 flags;
721 };
722 Q_DECLARE_TYPEINFO(TTF_POINT, Q_PRIMITIVE_TYPE);
723 
convertPath(const QPainterPath & path,QVector<TTF_POINT> * points,QVector<int> * endPoints,qreal ppem)724 static void convertPath(const QPainterPath &path, QVector<TTF_POINT> *points, QVector<int> *endPoints, qreal ppem)
725 {
726     int numElements = path.elementCount();
727     for (int i = 0; i < numElements - 1; ++i) {
728         const QPainterPath::Element &e = path.elementAt(i);
729         TTF_POINT p;
730         p.x = qRound(e.x * 2048. / ppem);
731         p.y = qRound(-e.y * 2048. / ppem);
732         p.flags = 0;
733 
734         switch(e.type) {
735         case QPainterPath::MoveToElement:
736             if (i != 0) {
737                 // see if start and end points of the last contour agree
738                 int start = endPoints->size() ? endPoints->at(endPoints->size()-1) - 1 : 0;
739                 int end = points->size() - 1;
740                 if (points->at(end).x == points->at(start).x
741                     && points->at(end).y == points->at(start).y)
742                     points->takeLast();
743                 endPoints->append(points->size() - 1);
744             }
745             Q_FALLTHROUGH();
746         case QPainterPath::LineToElement:
747             p.flags = OnCurve;
748             break;
749         case QPainterPath::CurveToElement: {
750             // cubic bezier curve, we need to reduce to a list of quadratic curves
751             TTF_POINT list[3*16 + 4]; // we need max 16 subdivisions
752             list[3] = points->at(points->size() - 1);
753             list[2] = p;
754             const QPainterPath::Element &e2 = path.elementAt(++i);
755             list[1].x = qRound(e2.x * 2048. / ppem);
756             list[1].y = qRound(-e2.y * 2048. / ppem);
757             const QPainterPath::Element &e3 = path.elementAt(++i);
758             list[0].x = qRound(e3.x * 2048. / ppem);
759             list[0].y = qRound(-e3.y * 2048. / ppem);
760 
761             TTF_POINT *base = list;
762 
763             bool try_reduce = points->size() > 1
764                               && points->at(points->size() - 1).flags == OnCurve
765                               && points->at(points->size() - 2).flags == OffCurve;
766 //             qDebug("generating beziers:");
767             while (base >= list) {
768                 const int split_limit = 3;
769 //                 {
770 //                     qDebug("iteration:");
771 //                     TTF_POINT *x = list;
772 //                     while (x <= base + 3) {
773 //                         qDebug() << "    " << QPoint(x->x, x->y);
774 //                         ++x;
775 //                     }
776 //                 }
777                 Q_ASSERT(base - list < 3*16 + 1);
778                 // first see if we can easily reduce the cubic to a quadratic bezier curve
779                 int i1_x = base[1].x + ((base[1].x - base[0].x) >> 1);
780                 int i1_y = base[1].y + ((base[1].y - base[0].y) >> 1);
781                 int i2_x = base[2].x + ((base[2].x - base[3].x) >> 1);
782                 int i2_y = base[2].y + ((base[2].y - base[3].y) >> 1);
783 //                 qDebug() << "checking: i1=" << QPoint(i1_x, i1_y) << " i2=" << QPoint(i2_x, i2_y);
784                 if (qAbs(i1_x - i2_x) <= split_limit && qAbs(i1_y - i2_y) <= split_limit) {
785                     // got a quadratic bezier curve
786                     TTF_POINT np;
787                     np.x = (i1_x + i2_x) >> 1;
788                     np.y = (i1_y + i2_y) >> 1;
789                     if (try_reduce) {
790                         // see if we can optimize out the last onCurve point
791                         int mx = (points->at(points->size() - 2).x + base[2].x) >> 1;
792                         int my = (points->at(points->size() - 2).y + base[2].y) >> 1;
793                         if (qAbs(mx - base[3].x) <= split_limit && qAbs(my - base[3].y) <= split_limit)
794                             points->takeLast();
795                         try_reduce = false;
796                     }
797                     np.flags = OffCurve;
798                     points->append(np);
799 //                     qDebug() << "   appending offcurve point " << QPoint(np.x, np.y);
800                     base -= 3;
801                 } else {
802                     // need to split
803 //                     qDebug("  -> splitting");
804                     qint16 a, b, c, d;
805                     base[6].x = base[3].x;
806                     c = base[1].x;
807                     d = base[2].x;
808                     base[1].x = a = ( base[0].x + c ) >> 1;
809                     base[5].x = b = ( base[3].x + d ) >> 1;
810                     c = ( c + d ) >> 1;
811                     base[2].x = a = ( a + c ) >> 1;
812                     base[4].x = b = ( b + c ) >> 1;
813                     base[3].x = ( a + b ) >> 1;
814 
815                     base[6].y = base[3].y;
816                     c = base[1].y;
817                     d = base[2].y;
818                     base[1].y = a = ( base[0].y + c ) >> 1;
819                     base[5].y = b = ( base[3].y + d ) >> 1;
820                     c = ( c + d ) >> 1;
821                     base[2].y = a = ( a + c ) >> 1;
822                     base[4].y = b = ( b + c ) >> 1;
823                     base[3].y = ( a + b ) >> 1;
824                     base += 3;
825                 }
826             }
827             p = list[0];
828             p.flags = OnCurve;
829             break;
830         }
831         case QPainterPath::CurveToDataElement:
832             Q_ASSERT(false);
833             break;
834         }
835 //         qDebug() << "   appending oncurve point " << QPoint(p.x, p.y);
836         points->append(p);
837     }
838     int start = endPoints->size() ? endPoints->at(endPoints->size()-1) + 1 : 0;
839     int end = points->size() - 1;
840     if (points->at(end).x == points->at(start).x
841         && points->at(end).y == points->at(start).y)
842         points->takeLast();
843     endPoints->append(points->size() - 1);
844 }
845 
getBounds(const QVector<TTF_POINT> & points,qint16 * xmin,qint16 * xmax,qint16 * ymin,qint16 * ymax)846 static void getBounds(const QVector<TTF_POINT> &points, qint16 *xmin, qint16 *xmax, qint16 *ymin, qint16 *ymax)
847 {
848     *xmin = points.at(0).x;
849     *xmax = *xmin;
850     *ymin = points.at(0).y;
851     *ymax = *ymin;
852 
853     for (int i = 1; i < points.size(); ++i) {
854         *xmin = qMin(*xmin, points.at(i).x);
855         *xmax = qMax(*xmax, points.at(i).x);
856         *ymin = qMin(*ymin, points.at(i).y);
857         *ymax = qMax(*ymax, points.at(i).y);
858     }
859 }
860 
convertToRelative(QVector<TTF_POINT> * points)861 static int convertToRelative(QVector<TTF_POINT> *points)
862 {
863     // convert points to relative and setup flags
864 //     qDebug("relative points:");
865     qint16 prev_x = 0;
866     qint16 prev_y = 0;
867     int point_array_size = 0;
868     for (int i = 0; i < points->size(); ++i) {
869         const int x = points->at(i).x;
870         const int y = points->at(i).y;
871         TTF_POINT rel;
872         rel.x = x - prev_x;
873         rel.y = y - prev_y;
874         rel.flags = points->at(i).flags;
875         Q_ASSERT(rel.flags < 2);
876         if (!rel.x) {
877             rel.flags |= XSame;
878         } else if (rel.x > 0 && rel.x < 256) {
879             rel.flags |= XShortVector|XShortPositive;
880             point_array_size++;
881         } else if (rel.x < 0 && rel.x > -256) {
882             rel.flags |= XShortVector;
883             rel.x = -rel.x;
884             point_array_size++;
885         } else {
886             point_array_size += 2;
887         }
888         if (!rel.y) {
889             rel.flags |= YSame;
890         } else if (rel.y > 0 && rel.y < 256) {
891             rel.flags |= YShortVector|YShortPositive;
892             point_array_size++;
893         } else if (rel.y < 0 && rel.y > -256) {
894             rel.flags |= YShortVector;
895             rel.y = -rel.y;
896             point_array_size++;
897         } else {
898             point_array_size += 2;
899         }
900         (*points)[i] = rel;
901 // #define toString(x) ((rel.flags & x) ? #x : "")
902 //         qDebug() << "    " << QPoint(rel.x, rel.y) << "flags="
903 //                  << toString(OnCurve) << toString(XShortVector)
904 //                  << (rel.flags & XShortVector ? toString(XShortPositive) : toString(XSame))
905 //                  << toString(YShortVector)
906 //                  << (rel.flags & YShortVector ? toString(YShortPositive) : toString(YSame));
907 
908         prev_x = x;
909         prev_y = y;
910     }
911     return point_array_size;
912 }
913 
getGlyphData(QTtfGlyph * glyph,const QVector<TTF_POINT> & points,const QVector<int> & endPoints,int point_array_size)914 static void getGlyphData(QTtfGlyph *glyph, const QVector<TTF_POINT> &points, const QVector<int> &endPoints, int point_array_size)
915 {
916     const int max_size = 5*sizeof(qint16) // header
917                          + endPoints.size()*sizeof(quint16) // end points of contours
918                          + sizeof(quint16) // instruction length == 0
919                          + points.size()*(1) // flags
920                          + point_array_size; // coordinates
921 
922     glyph->data.resize(max_size);
923 
924     QTtfStream s(glyph->data);
925     s << qint16(endPoints.size())
926       << glyph->xMin << glyph->yMin << glyph->xMax << glyph->yMax;
927 
928     for (int i = 0; i < endPoints.size(); ++i)
929         s << quint16(endPoints.at(i));
930     s << quint16(0); // instruction length
931 
932     // emit flags
933     for (int i = 0; i < points.size(); ++i)
934         s << quint8(points.at(i).flags);
935     // emit points
936     for (int i = 0; i < points.size(); ++i) {
937         quint8 flags = points.at(i).flags;
938         qint16 x = points.at(i).x;
939 
940         if (flags & XShortVector)
941             s << quint8(x);
942         else if (!(flags & XSame))
943             s << qint16(x);
944     }
945     for (int i = 0; i < points.size(); ++i) {
946         quint8 flags = points.at(i).flags;
947         qint16 y = points.at(i).y;
948 
949         if (flags & YShortVector)
950             s << quint8(y);
951         else if (!(flags & YSame))
952             s << qint16(y);
953     }
954 
955 //     qDebug() << "offset=" << s.offset() << "max_size=" << max_size << "point_array_size=" << point_array_size;
956     Q_ASSERT(s.offset() == max_size);
957 
958     glyph->numContours = endPoints.size();
959     glyph->numPoints = points.size();
960 }
961 
generateGlyph(int index,const QPainterPath & path,qreal advance,qreal lsb,qreal ppem)962 static QTtfGlyph generateGlyph(int index, const QPainterPath &path, qreal advance, qreal lsb, qreal ppem)
963 {
964     QVector<TTF_POINT> points;
965     QVector<int> endPoints;
966     QTtfGlyph glyph;
967     glyph.index = index;
968     glyph.advanceWidth = qRound(advance * 2048. / ppem);
969     glyph.lsb = qRound(lsb * 2048. / ppem);
970 
971     if (path.isEmpty()) {
972         //qDebug("glyph %d is empty", index);
973         lsb = 0;
974         glyph.xMin = glyph.xMax = glyph.yMin = glyph.yMax = 0;
975         glyph.numContours = 0;
976         glyph.numPoints = 0;
977         return glyph;
978     }
979 
980     convertPath(path, &points, &endPoints, ppem);
981 
982 //     qDebug() << "number of contours=" << endPoints.size();
983 //     for (int i = 0; i < points.size(); ++i)
984 //         qDebug() << "  point[" << i << "] = " << QPoint(points.at(i).x, points.at(i).y) << " flags=" << points.at(i).flags;
985 //     qDebug("endPoints:");
986 //     for (int i = 0; i < endPoints.size(); ++i)
987 //         qDebug() << endPoints.at(i);
988 
989     getBounds(points, &glyph.xMin, &glyph.xMax, &glyph.yMin, &glyph.yMax);
990     int point_array_size = convertToRelative(&points);
991     getGlyphData(&glyph, points, endPoints, point_array_size);
992     return glyph;
993 }
994 
operator <(const QTtfGlyph & g1,const QTtfGlyph & g2)995 static bool operator <(const QTtfGlyph &g1, const QTtfGlyph &g2)
996 {
997     return g1.index < g2.index;
998 }
999 
generateGlyphTables(qttf_font_tables & tables,const QVector<QTtfGlyph> & _glyphs)1000 static QVector<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QVector<QTtfGlyph> &_glyphs)
1001 {
1002     const int max_size_small = 65536*2;
1003     QVector<QTtfGlyph> glyphs = _glyphs;
1004     std::sort(glyphs.begin(), glyphs.end());
1005 
1006     Q_ASSERT(tables.maxp.numGlyphs == glyphs.at(glyphs.size()-1).index + 1);
1007     int nGlyphs = tables.maxp.numGlyphs;
1008 
1009     int glyf_size = 0;
1010     for (int i = 0; i < glyphs.size(); ++i)
1011         glyf_size += (glyphs.at(i).data.size() + 3) & ~3;
1012 
1013     tables.head.indexToLocFormat = glyf_size < max_size_small ? 0 : 1;
1014     tables.hhea.numberOfHMetrics = nGlyphs;
1015 
1016     QTtfTable glyf;
1017     glyf.tag = MAKE_TAG('g', 'l', 'y', 'f');
1018 
1019     QTtfTable loca;
1020     loca.tag = MAKE_TAG('l', 'o', 'c', 'a');
1021     loca.data.resize(glyf_size < max_size_small ? (nGlyphs+1)*sizeof(quint16) : (nGlyphs+1)*sizeof(quint32));
1022     QTtfStream ls(loca.data);
1023 
1024     QTtfTable hmtx;
1025     hmtx.tag = MAKE_TAG('h', 'm', 't', 'x');
1026     hmtx.data.resize(nGlyphs*4);
1027     QTtfStream hs(hmtx.data);
1028 
1029     int pos = 0;
1030     for (int i = 0; i < nGlyphs; ++i) {
1031         int gpos = glyf.data.size();
1032         quint16 advance = 0;
1033         qint16 lsb = 0;
1034 
1035         if (glyphs[pos].index == i) {
1036             // emit glyph
1037 //             qDebug("emitting glyph %d: size=%d", i, glyphs.at(i).data.size());
1038             glyf.data += glyphs.at(pos).data;
1039             while (glyf.data.size() & 1)
1040                 glyf.data.append('\0');
1041             advance = glyphs.at(pos).advanceWidth;
1042             lsb = glyphs.at(pos).lsb;
1043             ++pos;
1044         }
1045         if (glyf_size < max_size_small) {
1046             // use short loca format
1047             ls << quint16(gpos>>1);
1048         } else {
1049             // use long loca format
1050             ls << quint32(gpos);
1051         }
1052         hs << advance
1053            << lsb;
1054     }
1055     if (glyf_size < max_size_small) {
1056         // use short loca format
1057         ls << quint16(glyf.data.size()>>1);
1058     } else {
1059         // use long loca format
1060         ls << quint32(glyf.data.size());
1061     }
1062 
1063     Q_ASSERT(loca.data.size() == ls.offset());
1064     Q_ASSERT(hmtx.data.size() == hs.offset());
1065 
1066     QVector<QTtfTable> list;
1067     list.reserve(3);
1068     list.append(glyf);
1069     list.append(loca);
1070     list.append(hmtx);
1071     return list;
1072 }
1073 
operator <(const QTtfTable & t1,const QTtfTable & t2)1074 static bool operator <(const QTtfTable &t1, const QTtfTable &t2)
1075 {
1076     return t1.tag < t2.tag;
1077 }
1078 
bindFont(const QVector<QTtfTable> & _tables)1079 static QByteArray bindFont(const QVector<QTtfTable>& _tables)
1080 {
1081     QVector<QTtfTable> tables = _tables;
1082 
1083     std::sort(tables.begin(), tables.end());
1084 
1085     QByteArray font;
1086     const int header_size = sizeof(qint32) + 4*sizeof(quint16);
1087     const int directory_size = 4*sizeof(quint32)*tables.size();
1088     font.resize(header_size + directory_size);
1089 
1090     int log2 = 0;
1091     int pow = 1;
1092     int n = tables.size() >> 1;
1093     while (n) {
1094         ++log2;
1095         pow <<= 1;
1096         n >>= 1;
1097     }
1098 
1099     quint32 head_offset = 0;
1100     {
1101         QTtfStream f(font);
1102 // Offset Table
1103 // Type  Name  Description
1104 //   qint32  sfnt version  0x00010000 for version 1.0.
1105 //   quint16   numTables  Number of tables.
1106 //   quint16   searchRange  (Maximum power of 2 <= numTables) x 16.
1107 //   quint16   entrySelector  Log2(maximum power of 2 <= numTables).
1108 //   quint16   rangeShift  NumTables x 16-searchRange.
1109         f << qint32(0x00010000)
1110           << quint16(tables.size())
1111           << quint16(16*pow)
1112           << quint16(log2)
1113           << quint16(16*(tables.size() - pow));
1114 
1115 // Table Directory
1116 // Type  Name  Description
1117 //   quint32  tag  4 -byte identifier.
1118 //   quint32  checkSum  CheckSum for this table.
1119 //   quint32  offset  Offset from beginning of TrueType font file.
1120 //   quint32  length  Length of this table.
1121         quint32 table_offset = header_size + directory_size;
1122         for (int i = 0; i < tables.size(); ++i) {
1123             const QTtfTable &t = tables.at(i);
1124             const quint32 size = (t.data.size() + 3) & ~3;
1125             if (t.tag == MAKE_TAG('h', 'e', 'a', 'd'))
1126                 head_offset = table_offset;
1127             f << t.tag
1128               << checksum(t.data)
1129               << table_offset
1130               << t.data.size();
1131             table_offset += size;
1132 #define TAG(x) char(t.tag >> 24) << char((t.tag >> 16) & 0xff) << char((t.tag >> 8) & 0xff) << char(t.tag & 0xff)
1133             //qDebug() << "table " << TAG(t.tag) << "has size " << t.data.size() << "stream at " << f.offset();
1134         }
1135     }
1136     for (int i = 0; i < tables.size(); ++i) {
1137         const QByteArray &t = tables.at(i).data;
1138         font += t;
1139         int s = t.size();
1140         while (s & 3) { font += '\0'; ++s; }
1141     }
1142 
1143     if (!head_offset) {
1144         qWarning("QFontSubset: Font misses 'head' table");
1145         return QByteArray();
1146     }
1147 
1148     // calculate the fonts checksum and qToBigEndian into 'head's checksum_adjust
1149     quint32 checksum_adjust = 0xB1B0AFBA - checksum(font);
1150     qToBigEndian(checksum_adjust, font.data() + head_offset + 8);
1151 
1152     return font;
1153 }
1154 
1155 
1156 /*
1157   PDF requires the following tables:
1158 
1159   head, hhea, loca, maxp, cvt , prep, glyf, hmtx, fpgm
1160 
1161   This means we don't have to add a os/2, post or name table. cvt , prep and fpgm could be empty
1162   if really required.
1163 */
1164 
toTruetype() const1165 QByteArray QFontSubset::toTruetype() const
1166 {
1167     qttf_font_tables font;
1168     memset(&font, 0, sizeof(qttf_font_tables));
1169 
1170     qreal ppem = fontEngine->fontDef.pixelSize;
1171 #define TO_TTF(x) qRound(x * 2048. / ppem)
1172 
1173     QFontEngine::Properties properties = fontEngine->properties();
1174     // initialize some stuff needed in createWidthArray
1175     emSquare = 2048;
1176     widths.resize(nGlyphs());
1177 
1178     // head table
1179     font.head.font_revision = 0x00010000;
1180     font.head.flags = (1 << 2) | (1 << 4);
1181     font.head.created = 0; // ###
1182     font.head.modified = 0; // ###
1183     font.head.xMin = SHRT_MAX;
1184     font.head.xMax = SHRT_MIN;
1185     font.head.yMin = SHRT_MAX;
1186     font.head.yMax = SHRT_MIN;
1187     font.head.macStyle = (fontEngine->fontDef.weight > QFont::Normal) ? 1 : 0;
1188     font.head.macStyle |= (fontEngine->fontDef.styleHint != QFont::StyleNormal) ? 1 : 0;
1189 
1190     // hhea table
1191     font.hhea.ascender = qRound(properties.ascent);
1192     font.hhea.descender = -qRound(properties.descent);
1193     font.hhea.lineGap = qRound(properties.leading);
1194     font.hhea.maxAdvanceWidth = TO_TTF(fontEngine->maxCharWidth());
1195     font.hhea.minLeftSideBearing = TO_TTF(fontEngine->minLeftBearing());
1196     font.hhea.minRightSideBearing = TO_TTF(fontEngine->minRightBearing());
1197     font.hhea.xMaxExtent = SHRT_MIN;
1198 
1199     font.maxp.numGlyphs = 0;
1200     font.maxp.maxPoints = 0;
1201     font.maxp.maxContours = 0;
1202     font.maxp.maxCompositePoints = 0;
1203     font.maxp.maxCompositeContours = 0;
1204     font.maxp.maxComponentElements = 0;
1205     font.maxp.maxComponentDepth = 0;
1206     const int numGlyphs = nGlyphs();
1207     font.maxp.numGlyphs = numGlyphs;
1208     QVector<QTtfGlyph> glyphs;
1209     glyphs.reserve(numGlyphs);
1210 
1211     uint sumAdvances = 0;
1212     for (int i = 0; i < numGlyphs; ++i) {
1213         glyph_t g = glyph_indices.at(i);
1214         QPainterPath path;
1215         glyph_metrics_t metric;
1216         fontEngine->getUnscaledGlyph(g, &path, &metric);
1217         if (noEmbed) {
1218             path = QPainterPath();
1219             if (g == 0)
1220                 path.addRect(QRectF(0, 0, 1000, 1000));
1221         }
1222         QTtfGlyph glyph = generateGlyph(i, path, metric.xoff.toReal(), metric.x.toReal(), properties.emSquare.toReal());
1223 
1224         font.head.xMin = qMin(font.head.xMin, glyph.xMin);
1225         font.head.xMax = qMax(font.head.xMax, glyph.xMax);
1226         font.head.yMin = qMin(font.head.yMin, glyph.yMin);
1227         font.head.yMax = qMax(font.head.yMax, glyph.yMax);
1228 
1229         font.hhea.xMaxExtent = qMax(font.hhea.xMaxExtent, (qint16)(glyph.lsb + glyph.xMax - glyph.xMin));
1230 
1231         font.maxp.maxPoints = qMax(font.maxp.maxPoints, glyph.numPoints);
1232         font.maxp.maxContours = qMax(font.maxp.maxContours, glyph.numContours);
1233 
1234         if (glyph.xMax > glyph.xMin)
1235             sumAdvances += glyph.xMax - glyph.xMin;
1236 
1237 //         qDebug("adding glyph %d size=%d", glyph.index, glyph.data.size());
1238         glyphs.append(glyph);
1239         widths[i] = glyph.advanceWidth;
1240     }
1241 
1242 
1243     QVector<QTtfTable> tables = generateGlyphTables(font, glyphs);
1244     tables.append(generateHead(font.head));
1245     tables.append(generateHhea(font.hhea));
1246     tables.append(generateMaxp(font.maxp));
1247     // name
1248     QTtfTable name_table;
1249     name_table.tag = MAKE_TAG('n', 'a', 'm', 'e');
1250     if (!noEmbed)
1251         name_table.data = fontEngine->getSfntTable(name_table.tag);
1252     if (name_table.data.isEmpty()) {
1253         qttf_name_table name;
1254         if (noEmbed)
1255             name.copyright = QLatin1String("Fake font");
1256         else
1257             name.copyright = QLatin1String(properties.copyright);
1258         name.family = fontEngine->fontDef.family;
1259         name.subfamily = QLatin1String("Regular"); // ######
1260         name.postscript_name = QLatin1String(properties.postscriptName);
1261         name_table = generateName(name);
1262     }
1263     tables.append(name_table);
1264 
1265     if (!noEmbed) {
1266         QTtfTable os2;
1267         os2.tag = MAKE_TAG('O', 'S', '/', '2');
1268         os2.data = fontEngine->getSfntTable(os2.tag);
1269         if (!os2.data.isEmpty())
1270             tables.append(os2);
1271     }
1272 
1273     return bindFont(tables);
1274 }
1275 
1276 QT_END_NAMESPACE
1277