QtBase  v6.3.1
qfontsubset.cpp
Go to the documentation of this file.
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 
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 
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 
115 QByteArray QFontSubset::glyphName(unsigned int glyph, const QList<int> &reverseMap) const
116 {
117  uint glyphIndex = glyph_indices[glyph];
118 
119  if (glyphIndex == 0)
120  return "/.notdef";
121 
122  QByteArray 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 
134 {
135  Q_ASSERT(!widths.isEmpty());
136 
138 
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 
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 
201 {
202  QList<int> reverseMap(0x10000, 0);
203  for (uint uc = 0; uc < 0x10000; ++uc) {
205  if (idx >= 0 && !reverseMap.at(idx))
206  reverseMap[idx] = uc;
207  }
208  return reverseMap;
209 }
210 
212 {
213  QList<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 
304 {
306  if (idx < 0) {
307  idx = glyph_indices.size();
309  }
310  return (int)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:
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 {
345 };
347 
348 
360 };
362 
363 
373 };
375 
376 
385 };
387 
393 };
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 
403 {
407 };
408 
409 
410 struct QTtfGlyph {
421 };
423 
424 static QTtfGlyph generateGlyph(int index, const QPainterPath &path, qreal advance, qreal lsb, qreal ppem);
425 // generates glyf, loca and hmtx
426 static QList<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QList<QTtfGlyph> &_glyphs);
427 
428 static QByteArray bindFont(const QList<QTtfTable>& _tables);
429 
430 
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 
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 
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 
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 
621 };
623 
624 static QTtfTable generateName(const QList<QTtfNameRecord> &name);
625 
626 static QTtfTable generateName(const qttf_name_table &name)
627 {
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
653 static QTtfTable generateName(const QList<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 {
721 };
723 
724 static void convertPath(const QPainterPath &path, QList<TTF_POINT> *points, QList<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) {
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();
747  p.flags = OnCurve;
748  break;
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  }
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 
846 static void getBounds(const QList<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 
861 static int convertToRelative(QList<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) {
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) {
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 
914 static void getGlyphData(QTtfGlyph *glyph, const QList<TTF_POINT> &points, const QList<int> &endPoints, int point_array_size)
915 {
916  const int max_size = int(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 
962 static QTtfGlyph generateGlyph(int index, const QPainterPath &path, qreal advance, qreal lsb, qreal ppem)
963 {
965  QList<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 
995 static bool operator <(const QTtfGlyph &g1, const QTtfGlyph &g2)
996 {
997  return g1.index < g2.index;
998 }
999 
1000 static QList<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QList<QTtfGlyph> &_glyphs)
1001 {
1002  const int max_size_small = 65536*2;
1003  QList<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 
1067  list.reserve(3);
1068  list.append(glyf);
1069  list.append(loca);
1070  list.append(hmtx);
1071  return list;
1072 }
1073 
1074 static bool operator <(const QTtfTable &t1, const QTtfTable &t2)
1075 {
1076  return t1.tag < t2.tag;
1077 }
1078 
1079 static QByteArray bindFont(const QList<QTtfTable>& _tables)
1080 {
1081  QList<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  << quint32(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 
1166 {
1168  memset(&font, 0, sizeof(qttf_font_tables));
1169 
1171 #define TO_TTF(x) qRound(x * 2048. / ppem)
1172 
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  QList<QTtfGlyph> glyphs;
1209  glyphs.reserve(numGlyphs);
1210 
1211  for (int i = 0; i < numGlyphs; ++i) {
1212  glyph_t g = glyph_indices.at(i);
1214  glyph_metrics_t metric;
1215  fontEngine->getUnscaledGlyph(g, &path, &metric);
1216  if (noEmbed) {
1217  path = QPainterPath();
1218  if (g == 0)
1219  path.addRect(QRectF(0, 0, 1000, 1000));
1220  }
1221  QTtfGlyph glyph = generateGlyph(i, path, metric.xoff.toReal(), metric.x.toReal(), properties.emSquare.toReal());
1222 
1223  font.head.xMin = qMin(font.head.xMin, glyph.xMin);
1224  font.head.xMax = qMax(font.head.xMax, glyph.xMax);
1225  font.head.yMin = qMin(font.head.yMin, glyph.yMin);
1226  font.head.yMax = qMax(font.head.yMax, glyph.yMax);
1227 
1228  font.hhea.xMaxExtent = qMax(font.hhea.xMaxExtent, (qint16)(glyph.lsb + glyph.xMax - glyph.xMin));
1229 
1230  font.maxp.maxPoints = qMax(font.maxp.maxPoints, glyph.numPoints);
1231  font.maxp.maxContours = qMax(font.maxp.maxContours, glyph.numContours);
1232 
1233 // qDebug("adding glyph %d size=%d", glyph.index, glyph.data.size());
1234  glyphs.append(glyph);
1235  widths[i] = glyph.advanceWidth;
1236  }
1237 
1238 
1239  QList<QTtfTable> tables = generateGlyphTables(font, glyphs);
1240  tables.append(generateHead(font.head));
1241  tables.append(generateHhea(font.hhea));
1242  tables.append(generateMaxp(font.maxp));
1243  // name
1244  QTtfTable name_table;
1245  name_table.tag = MAKE_TAG('n', 'a', 'm', 'e');
1246  if (!noEmbed)
1247  name_table.data = fontEngine->getSfntTable(name_table.tag);
1248  if (name_table.data.isEmpty()) {
1250  if (noEmbed)
1251  name.copyright = QLatin1String("Fake font");
1252  else
1253  name.copyright = QLatin1String(properties.copyright);
1254  name.family = fontEngine->fontDef.families.first();
1255  name.subfamily = QLatin1String("Regular"); // ######
1256  name.postscript_name = QLatin1String(properties.postscriptName);
1257  name_table = generateName(name);
1258  }
1259  tables.append(name_table);
1260 
1261  if (!noEmbed) {
1262  QTtfTable os2;
1263  os2.tag = MAKE_TAG('O', 'S', '/', '2');
1264  os2.data = fontEngine->getSfntTable(os2.tag);
1265  if (!os2.data.isEmpty())
1266  tables.append(os2);
1267  }
1268 
1269  return bindFont(tables);
1270 }
1271 
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
FT_UInt idx
Definition: cffcmap.c:135
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
qsizetype size() const noexcept
Definition: qbytearray.h:470
bool isEmpty() const noexcept
Definition: qbytearray.h:129
void resize(qsizetype size)
QByteArray & append(char c)
bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
virtual Properties properties() const
virtual qreal minRightBearing() const
virtual qreal minLeftBearing() const
virtual qreal maxCharWidth() const =0
virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
QFontDef fontDef
QByteArray getSfntTable(uint tag) const
virtual glyph_t glyphIndex(uint ucs4) const =0
@ Normal
Definition: qfont.h:100
@ StyleNormal
Definition: qfont.h:110
QFontEngine * fontEngine
Definition: qfontsubset_p.h:88
QByteArray toTruetype() const
QByteArray glyphName(unsigned int glyph, const QList< int > &reverseMap) const
int addGlyph(uint index)
QFixed emSquare
Definition: qfontsubset_p.h:93
QList< int > getReverseMap() const
QList< QFixed > widths
Definition: qfontsubset_p.h:94
QByteArray createToUnicodeMap() const
QList< uint > glyph_indices
Definition: qfontsubset_p.h:89
QByteArray widthArray() const
int nGlyphs() const
Definition: qfontsubset_p.h:92
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
qsizetype size() const noexcept
Definition: qlist.h:414
bool isEmpty() const noexcept
Definition: qlist.h:418
iterator end()
Definition: qlist.h:624
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
iterator begin()
Definition: qlist.h:623
void reserve(qsizetype size)
Definition: qlist.h:757
void resize(qsizetype size)
Definition: qlist.h:420
void append(parameter_type t)
Definition: qlist.h:469
The QPainterPath::Element class specifies the position and type of a subpath.
Definition: qpainterpath.h:74
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:65
The QRectF class defines a finite rectangle in the plane using floating point precision.
Definition: qrect.h:511
The QString class provides a Unicode character string.
Definition: qstring.h:388
const QChar at(qsizetype i) const
Definition: qstring.h:1212
QTtfStream & operator<<(quint8 v)
void setOffset(int o)
void align4()
QTtfStream(QByteArray &ba)
int offset() const
int y
the y coordinate of the widget relative to its parent and including any window frame
Definition: qwidget.h:144
int x
the x coordinate of the widget relative to its parent including any window frame
Definition: qwidget.h:143
Definition: base.h:37
double e
HeaderSize header_size(const HttpHeader &header)
Definition: hpack.cpp:53
const char * toHex(ushort u, char *buffer)
Definition: qpdf.cpp:749
#define Q_FALLTHROUGH()
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
constexpr T qToBigEndian(T source)
Definition: qendian.h:187
int qRound(qfloat16 d) noexcept
Definition: qfloat16.h:227
#define MAKE_TAG(ch1, ch2, ch3, ch4)
Definition: qfontengine_p.h:68
Q_DECLARE_TYPEINFO(QTtfTable, Q_RELOCATABLE_TYPE)
quint32 Tag
qint16 F2DOT14
Flags
@ YSame
@ YShortPositive
@ OffCurve
@ XShortPositive
@ OnCurve
@ XShortVector
@ Repeat
@ YShortVector
@ XSame
quint16 GlyphID
quint16 Offset
#define TO_TTF(x)
unsigned int quint32
Definition: qglobal.h:288
short qint16
Definition: qglobal.h:285
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
Definition: qglobal.h:332
unsigned short quint16
Definition: qglobal.h:286
int qint32
Definition: qglobal.h:287
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
ptrdiff_t qsizetype
Definition: qglobal.h:308
unsigned int uint
Definition: qglobal.h:334
long long qint64
Definition: qglobal.h:298
unsigned short ushort
Definition: qglobal.h:333
QT_BEGIN_NAMESPACE typedef signed char qint8
Definition: qglobal.h:283
unsigned char quint8
Definition: qglobal.h:284
#define qWarning
Definition: qlogging.h:179
bool int shift
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLboolean r
[2]
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum const void GLbitfield GLsizei numGlyphs
GLfloat GLfloat f
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
[4]
GLenum GLuint buffer
GLint GLsizei width
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLuint name
GLfloat n
GLint y
GLfixed GLfixed GLint GLint GLfixed points
Definition: qopenglext.h:5206
const GLubyte * c
Definition: qopenglext.h:12701
GLenum GLsizei len
Definition: qopenglext.h:3292
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLsizei const GLchar *const * path
Definition: qopenglext.h:4283
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLenum GLenum GLenum GLenum GLenum scale
Definition: qopenglext.h:10817
GLenum GLenum GLsizei void * table
Definition: qopenglext.h:2745
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QPointF qAbs(const QPointF &p)
Definition: qscroller.cpp:119
unsigned int glyph_t
@ Q_PRIMITIVE_TYPE
Definition: qtypeinfo.h:155
@ Q_RELOCATABLE_TYPE
Definition: qtypeinfo.h:156
QFuture< int > sum
QByteArray ba
[0]
QSize t2(10, 12)
QStringList list
[0]
constexpr int toInt() const
Definition: qfixed_p.h:77
constexpr qreal toReal() const
Definition: qfixed_p.h:78
qreal pixelSize
Definition: qfont_p.h:96
uint weight
Definition: qfont_p.h:105
QStringList families
Definition: qfont_p.h:90
uint styleHint
Definition: qfont_p.h:104
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition: qlist.h:966
QByteArray data
qint16 yMin
quint16 numPoints
qint16 xMin
quint16 advanceWidth
qint16 lsb
qint16 yMax
quint16 index
qint16 xMax
quint16 numContours
QByteArray data
quint8 flags
Definition: data.cpp:95
qttf_head_table head
qttf_maxp_table maxp
qttf_hhea_table hhea
qint16 indexToLocFormat
quint16 maxAdvanceWidth
qint16 minLeftSideBearing
qint16 minRightSideBearing
quint16 numberOfHMetrics
quint16 maxCompositeContours
quint16 maxCompositePoints
quint16 maxComponentElements
quint16 maxComponentDepth
QString postscript_name