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