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