Export QTextImageHandler and add accessor for image
[profile/ivi/qtbase.git] / src / gui / text / qfontsubset.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qdebug.h>
42 #include "qfontsubset_p.h"
43 #include <qendian.h>
44 #include <qpainterpath.h>
45 #include "private/qpdf_p.h"
46 #include "private/qfunctions_p.h"
47
48 #ifdef Q_WS_X11
49 #include "private/qfontengine_x11_p.h"
50 #endif
51
52 #ifndef QT_NO_FREETYPE
53 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
54 #    include "private/qfontengine_ft_p.h"
55 #endif
56 #include <ft2build.h>
57 #include FT_FREETYPE_H
58 #endif
59
60 QT_BEGIN_NAMESPACE
61
62 static const char * const agl =
63 ".notdef\0space\0exclam\0quotedbl\0numbersign\0dollar\0percent\0ampersand\0"
64 "quotesingle\0parenleft\0parenright\0asterisk\0plus\0comma\0hyphen\0period\0"
65 "slash\0zero\0one\0two\0three\0four\0five\0six\0seven\0eight\0nine\0colon\0"
66 "semicolon\0less\0equal\0greater\0question\0at\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0"
67 "K\0L\0M\0N\0O\0P\0Q\0R\0S\0T\0U\0V\0W\0X\0Y\0Z\0bracketleft\0backslash\0"
68 "bracketright\0asciicircum\0underscore\0grave\0a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0"
69 "k\0l\0m\0n\0o\0p\0q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0braceleft\0bar\0braceright\0"
70 "asciitilde\0space\0exclamdown\0cent\0sterling\0currency\0yen\0brokenbar\0"
71 "section\0dieresis\0copyright\0ordfeminine\0guillemotleft\0logicalnot\0"
72 "hyphen\0registered\0macron\0degree\0plusminus\0twosuperior\0threesuperior\0"
73 "acute\0mu\0paragraph\0periodcentered\0cedilla\0onesuperior\0ordmasculine\0"
74 "guillemotright\0onequarter\0onehalf\0threequarters\0questiondown\0Agrave\0"
75 "Aacute\0Acircumflex\0Atilde\0Adieresis\0Aring\0AE\0Ccedilla\0Egrave\0Eacute\0"
76 "Ecircumflex\0Edieresis\0Igrave\0Iacute\0Icircumflex\0Idieresis\0Eth\0Ntilde\0"
77 "Ograve\0Oacute\0Ocircumflex\0Otilde\0Odieresis\0multiply\0Oslash\0Ugrave\0"
78 "Uacute\0Ucircumflex\0Udieresis\0Yacute\0Thorn\0germandbls\0agrave\0aacute\0"
79 "acircumflex\0atilde\0adieresis\0aring\0ae\0ccedilla\0egrave\0eacute\0"
80 "ecircumflex\0edieresis\0igrave\0iacute\0icircumflex\0idieresis\0eth\0ntilde\0"
81 "ograve\0oacute\0ocircumflex\0otilde\0odieresis\0divide\0oslash\0ugrave\0"
82 "uacute\0ucircumflex\0udieresis\0yacute\0thorn\0ydieresis\0Amacron\0amacron\0"
83 "Abreve\0abreve\0Aogonek\0aogonek\0Cacute\0cacute\0Ccircumflex\0ccircumflex\0"
84 "Cdotaccent\0cdotaccent\0Ccaron\0ccaron\0Dcaron\0dcaron\0Dcroat\0dcroat\0"
85 "Emacron\0emacron\0Ebreve\0ebreve\0Edotaccent\0edotaccent\0Eogonek\0eogonek\0"
86 "Ecaron\0ecaron\0Gcircumflex\0gcircumflex\0Gbreve\0gbreve\0Gdotaccent\0"
87 "gdotaccent\0Gcommaaccent\0gcommaaccent\0Hcircumflex\0hcircumflex\0Hbar\0"
88 "hbar\0Itilde\0itilde\0Imacron\0imacron\0Ibreve\0ibreve\0Iogonek\0iogonek\0"
89 "Idotaccent\0dotlessi\0IJ\0ij\0Jcircumflex\0jcircumflex\0Kcommaaccent\0"
90 "kcommaaccent\0kgreenlandic\0Lacute\0lacute\0Lcommaaccent\0lcommaaccent\0"
91 "Lcaron\0lcaron\0Ldot\0ldot\0Lslash\0lslash\0Nacute\0nacute\0Ncommaaccent\0"
92 "ncommaaccent\0Ncaron\0ncaron\0napostrophe\0Eng\0eng\0Omacron\0omacron\0"
93 "Obreve\0obreve\0Ohungarumlaut\0ohungarumlaut\0OE\0oe\0Racute\0racute\0"
94 "Rcommaaccent\0rcommaaccent\0Rcaron\0rcaron\0Sacute\0sacute\0Scircumflex\0"
95 "scircumflex\0Scedilla\0scedilla\0Scaron\0scaron\0Tcaron\0tcaron\0Tbar\0tbar\0"
96 "Utilde\0utilde\0Umacron\0umacron\0Ubreve\0ubreve\0Uring\0uring\0"
97 "Uhungarumlaut\0uhungarumlaut\0Uogonek\0uogonek\0Wcircumflex\0wcircumflex\0"
98 "Ycircumflex\0ycircumflex\0Ydieresis\0Zacute\0zacute\0Zdotaccent\0zdotaccent\0"
99 "Zcaron\0zcaron\0longs\0florin\0Ohorn\0ohorn\0Uhorn\0uhorn\0Gcaron\0gcaron\0"
100 "Aringacute\0aringacute\0AEacute\0aeacute\0Oslashacute\0oslashacute\0"
101 "Scommaaccent\0scommaaccent\0Tcommaaccent\0tcommaaccent\0afii57929\0"
102 "afii64937\0circumflex\0caron\0breve\0dotaccent\0ring\0ogonek\0tilde\0"
103 "hungarumlaut\0gravecomb\0acutecomb\0tildecomb\0hookabovecomb\0dotbelowcomb\0"
104 "tonos\0dieresistonos\0Alphatonos\0anoteleia\0Epsilontonos\0Etatonos\0"
105 "Iotatonos\0Omicrontonos\0Upsilontonos\0Omegatonos\0iotadieresistonos\0Alpha\0"
106 "Beta\0Gamma\0Delta\0Epsilon\0Zeta\0Eta\0Theta\0Iota\0Kappa\0Lambda\0Mu\0Nu\0"
107 "Xi\0Omicron\0Pi\0Rho\0Sigma\0Tau\0Upsilon\0Phi\0Chi\0Psi\0Omega\0"
108 "Iotadieresis\0Upsilondieresis\0alphatonos\0epsilontonos\0etatonos\0"
109 "iotatonos\0upsilondieresistonos\0alpha\0beta\0gamma\0delta\0epsilon\0zeta\0"
110 "eta\0theta\0iota\0kappa\0lambda\0mu\0nu\0xi\0omicron\0pi\0rho\0sigma1\0"
111 "sigma\0tau\0upsilon\0phi\0chi\0psi\0omega\0iotadieresis\0upsilondieresis\0"
112 ;
113
114 static const struct { quint16 u; quint16 index; } unicode_to_aglindex[] = {
115     {0x0000, 0}, {0x0020, 8}, {0x0021, 14}, {0x0022, 21},
116     {0x0023, 30}, {0x0024, 41}, {0x0025, 48}, {0x0026, 56},
117     {0x0027, 66}, {0x0028, 78}, {0x0029, 88}, {0x002A, 99},
118     {0x002B, 108}, {0x002C, 113}, {0x002D, 119}, {0x002E, 126},
119     {0x002F, 133}, {0x0030, 139}, {0x0031, 144}, {0x0032, 148},
120     {0x0033, 152}, {0x0034, 158}, {0x0035, 163}, {0x0036, 168},
121     {0x0037, 172}, {0x0038, 178}, {0x0039, 184}, {0x003A, 189},
122     {0x003B, 195}, {0x003C, 205}, {0x003D, 210}, {0x003E, 216},
123     {0x003F, 224}, {0x0040, 233}, {0x0041, 236}, {0x0042, 238},
124     {0x0043, 240}, {0x0044, 242}, {0x0045, 244}, {0x0046, 246},
125     {0x0047, 248}, {0x0048, 250}, {0x0049, 252}, {0x004A, 254},
126     {0x004B, 256}, {0x004C, 258}, {0x004D, 260}, {0x004E, 262},
127     {0x004F, 264}, {0x0050, 266}, {0x0051, 268}, {0x0052, 270},
128     {0x0053, 272}, {0x0054, 274}, {0x0055, 276}, {0x0056, 278},
129     {0x0057, 280}, {0x0058, 282}, {0x0059, 284}, {0x005A, 286},
130     {0x005B, 288}, {0x005C, 300}, {0x005D, 310}, {0x005E, 323},
131     {0x005F, 335}, {0x0060, 346}, {0x0061, 352}, {0x0062, 354},
132     {0x0063, 356}, {0x0064, 358}, {0x0065, 360}, {0x0066, 362},
133     {0x0067, 364}, {0x0068, 366}, {0x0069, 368}, {0x006A, 370},
134     {0x006B, 372}, {0x006C, 374}, {0x006D, 376}, {0x006E, 378},
135     {0x006F, 380}, {0x0070, 382}, {0x0071, 384}, {0x0072, 386},
136     {0x0073, 388}, {0x0074, 390}, {0x0075, 392}, {0x0076, 394},
137     {0x0077, 396}, {0x0078, 398}, {0x0079, 400}, {0x007A, 402},
138     {0x007B, 404}, {0x007C, 414}, {0x007D, 418}, {0x007E, 429},
139     {0x00A0, 440}, {0x00A1, 446}, {0x00A2, 457}, {0x00A3, 462},
140     {0x00A4, 471}, {0x00A5, 480}, {0x00A6, 484}, {0x00A7, 494},
141     {0x00A8, 502}, {0x00A9, 511}, {0x00AA, 521}, {0x00AB, 533},
142     {0x00AC, 547}, {0x00AD, 558}, {0x00AE, 565}, {0x00AF, 576},
143     {0x00B0, 583}, {0x00B1, 590}, {0x00B2, 600}, {0x00B3, 612},
144     {0x00B4, 626}, {0x00B5, 632}, {0x00B6, 635}, {0x00B7, 645},
145     {0x00B8, 660}, {0x00B9, 668}, {0x00BA, 680}, {0x00BB, 693},
146     {0x00BC, 708}, {0x00BD, 719}, {0x00BE, 727}, {0x00BF, 741},
147     {0x00C0, 754}, {0x00C1, 761}, {0x00C2, 768}, {0x00C3, 780},
148     {0x00C4, 787}, {0x00C5, 797}, {0x00C6, 803}, {0x00C7, 806},
149     {0x00C8, 815}, {0x00C9, 822}, {0x00CA, 829}, {0x00CB, 841},
150     {0x00CC, 851}, {0x00CD, 858}, {0x00CE, 865}, {0x00CF, 877},
151     {0x00D0, 887}, {0x00D1, 891}, {0x00D2, 898}, {0x00D3, 905},
152     {0x00D4, 912}, {0x00D5, 924}, {0x00D6, 931}, {0x00D7, 941},
153     {0x00D8, 950}, {0x00D9, 957}, {0x00DA, 964}, {0x00DB, 971},
154     {0x00DC, 983}, {0x00DD, 993}, {0x00DE, 1000}, {0x00DF, 1006},
155     {0x00E0, 1017}, {0x00E1, 1024}, {0x00E2, 1031}, {0x00E3, 1043},
156     {0x00E4, 1050}, {0x00E5, 1060}, {0x00E6, 1066}, {0x00E7, 1069},
157     {0x00E8, 1078}, {0x00E9, 1085}, {0x00EA, 1092}, {0x00EB, 1104},
158     {0x00EC, 1114}, {0x00ED, 1121}, {0x00EE, 1128}, {0x00EF, 1140},
159     {0x00F0, 1150}, {0x00F1, 1154}, {0x00F2, 1161}, {0x00F3, 1168},
160     {0x00F4, 1175}, {0x00F5, 1187}, {0x00F6, 1194}, {0x00F7, 1204},
161     {0x00F8, 1211}, {0x00F9, 1218}, {0x00FA, 1225}, {0x00FB, 1232},
162     {0x00FC, 1244}, {0x00FD, 1254}, {0x00FE, 1261}, {0x00FF, 1267},
163     {0x0100, 1277}, {0x0101, 1285}, {0x0102, 1293}, {0x0103, 1300},
164     {0x0104, 1307}, {0x0105, 1315}, {0x0106, 1323}, {0x0107, 1330},
165     {0x0108, 1337}, {0x0109, 1349}, {0x010A, 1361}, {0x010B, 1372},
166     {0x010C, 1383}, {0x010D, 1390}, {0x010E, 1397}, {0x010F, 1404},
167     {0x0110, 1411}, {0x0111, 1418}, {0x0112, 1425}, {0x0113, 1433},
168     {0x0114, 1441}, {0x0115, 1448}, {0x0116, 1455}, {0x0117, 1466},
169     {0x0118, 1477}, {0x0119, 1485}, {0x011A, 1493}, {0x011B, 1500},
170     {0x011C, 1507}, {0x011D, 1519}, {0x011E, 1531}, {0x011F, 1538},
171     {0x0120, 1545}, {0x0121, 1556}, {0x0122, 1567}, {0x0123, 1580},
172     {0x0124, 1593}, {0x0125, 1605}, {0x0126, 1617}, {0x0127, 1622},
173     {0x0128, 1627}, {0x0129, 1634}, {0x012A, 1641}, {0x012B, 1649},
174     {0x012C, 1657}, {0x012D, 1664}, {0x012E, 1671}, {0x012F, 1679},
175     {0x0130, 1687}, {0x0131, 1698}, {0x0132, 1707}, {0x0133, 1710},
176     {0x0134, 1713}, {0x0135, 1725}, {0x0136, 1737}, {0x0137, 1750},
177     {0x0138, 1763}, {0x0139, 1776}, {0x013A, 1783}, {0x013B, 1790},
178     {0x013C, 1803}, {0x013D, 1816}, {0x013E, 1823}, {0x013F, 1830},
179     {0x0140, 1835}, {0x0141, 1840}, {0x0142, 1847}, {0x0143, 1854},
180     {0x0144, 1861}, {0x0145, 1868}, {0x0146, 1881}, {0x0147, 1894},
181     {0x0148, 1901}, {0x0149, 1908}, {0x014A, 1920}, {0x014B, 1924},
182     {0x014C, 1928}, {0x014D, 1936}, {0x014E, 1944}, {0x014F, 1951},
183     {0x0150, 1958}, {0x0151, 1972}, {0x0152, 1986}, {0x0153, 1989},
184     {0x0154, 1992}, {0x0155, 1999}, {0x0156, 2006}, {0x0157, 2019},
185     {0x0158, 2032}, {0x0159, 2039}, {0x015A, 2046}, {0x015B, 2053},
186     {0x015C, 2060}, {0x015D, 2072}, {0x015E, 2084}, {0x015F, 2093},
187     {0x0160, 2102}, {0x0161, 2109}, {0x0164, 2116}, {0x0165, 2123},
188     {0x0166, 2130}, {0x0167, 2135}, {0x0168, 2140}, {0x0169, 2147},
189     {0x016A, 2154}, {0x016B, 2162}, {0x016C, 2170}, {0x016D, 2177},
190     {0x016E, 2184}, {0x016F, 2190}, {0x0170, 2196}, {0x0171, 2210},
191     {0x0172, 2224}, {0x0173, 2232}, {0x0174, 2240}, {0x0175, 2252},
192     {0x0176, 2264}, {0x0177, 2276}, {0x0178, 2288}, {0x0179, 2298},
193     {0x017A, 2305}, {0x017B, 2312}, {0x017C, 2323}, {0x017D, 2334},
194     {0x017E, 2341}, {0x017F, 2348}, {0x0192, 2354}, {0x01A0, 2361},
195     {0x01A1, 2367}, {0x01AF, 2373}, {0x01B0, 2379}, {0x01E6, 2385},
196     {0x01E7, 2392}, {0x01FA, 2399}, {0x01FB, 2410}, {0x01FC, 2421},
197     {0x01FD, 2429}, {0x01FE, 2437}, {0x01FF, 2449}, {0x0218, 2461},
198     {0x0219, 2474}, {0x021A, 2487}, {0x021B, 2500}, {0x02BC, 2513},
199     {0x02BD, 2523}, {0x02C6, 2533}, {0x02C7, 2544}, {0x02D8, 2550},
200     {0x02D9, 2556}, {0x02DA, 2566}, {0x02DB, 2571}, {0x02DC, 2578},
201     {0x02DD, 2584}, {0x0300, 2597}, {0x0301, 2607}, {0x0303, 2617},
202     {0x0309, 2627}, {0x0323, 2641}, {0x0384, 2654}, {0x0385, 2660},
203     {0x0386, 2674}, {0x0387, 2685}, {0x0388, 2695}, {0x0389, 2708},
204     {0x038A, 2717}, {0x038C, 2727}, {0x038E, 2740}, {0x038F, 2753},
205     {0x0390, 2764}, {0x0391, 2782}, {0x0392, 2788}, {0x0393, 2793},
206     {0x0394, 2799}, {0x0395, 2805}, {0x0396, 2813}, {0x0397, 2818},
207     {0x0398, 2822}, {0x0399, 2828}, {0x039A, 2833}, {0x039B, 2839},
208     {0x039C, 2846}, {0x039D, 2849}, {0x039E, 2852}, {0x039F, 2855},
209     {0x03A0, 2863}, {0x03A1, 2866}, {0x03A3, 2870}, {0x03A4, 2876},
210     {0x03A5, 2880}, {0x03A6, 2888}, {0x03A7, 2892}, {0x03A8, 2896},
211     {0x03A9, 2900}, {0x03AA, 2906}, {0x03AB, 2919}, {0x03AC, 2935},
212     {0x03AD, 2946}, {0x03AE, 2959}, {0x03AF, 2968}, {0x03B0, 2978},
213     {0x03B1, 2999}, {0x03B2, 3005}, {0x03B3, 3010}, {0x03B4, 3016},
214     {0x03B5, 3022}, {0x03B6, 3030}, {0x03B7, 3035}, {0x03B8, 3039},
215     {0x03B9, 3045}, {0x03BA, 3050}, {0x03BB, 3056}, {0x03BC, 3063},
216     {0x03BD, 3066}, {0x03BE, 3069}, {0x03BF, 3072}, {0x03C0, 3080},
217     {0x03C1, 3083}, {0x03C2, 3087}, {0x03C3, 3094}, {0x03C4, 3100},
218     {0x03C5, 3104}, {0x03C6, 3112}, {0x03C7, 3116}, {0x03C8, 3120},
219     {0x03C9, 3124}, {0x03CA, 3130}, {0x03CB, 3143}, {0x03CC, 3159},
220     {0x03CD, 3172}, {0x03CE, 3185}, {0x03D1, 3196}, {0x03D2, 3203},
221     {0x03D5, 3212}, {0x03D6, 3217}, {0xFFFF, 3224}
222 };
223
224 // This map is used for symbol fonts to get the correct glyph names for the latin range
225 static const unsigned short symbol_map[0x100] = {
226     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
227     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
228     0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
229     0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
230     0x0020, 0x0021, 0x2200, 0x0023, 0x2203, 0x0025, 0x0026, 0x220b,
231     0x0028, 0x0029, 0x2217, 0x002b, 0x002c, 0x2212, 0x002e, 0x002f,
232     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
233     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
234
235     0x2245, 0x0391, 0x0392, 0x03a7, 0x0394, 0x0395, 0x03a6, 0x0393,
236     0x0397, 0x0399, 0x03d1, 0x039a, 0x039b, 0x039c, 0x039d, 0x039f,
237     0x03a0, 0x0398, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03c2, 0x03a9,
238     0x039e, 0x03a8, 0x0396, 0x005b, 0x2234, 0x005d, 0x22a5, 0x005f,
239     0xf8e5, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3,
240     0x03b7, 0x03b9, 0x03d5, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03bf,
241     0x03c0, 0x03b8, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03d6, 0x03c9,
242     0x03be, 0x03c8, 0x03b6, 0x007b, 0x007c, 0x007d, 0x223c, 0x007f,
243
244     0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
245     0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
246     0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
247     0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
248     0x20ac, 0x03d2, 0x2023, 0x2264, 0x2044, 0x221e, 0x0192, 0x2263,
249     0x2666, 0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193,
250     0x00b0, 0x00b1, 0x2033, 0x2265, 0x00d7, 0x221d, 0x2202, 0x2022,
251     0x00f7, 0x2260, 0x2261, 0x2248, 0x2026, 0xf8e6, 0xf8e7, 0x21b5,
252
253     0x2135, 0x2111, 0x211c, 0x2118, 0x2297, 0x2295, 0x2205, 0x2229,
254     0x222a, 0x2283, 0x2287, 0x2284, 0x2282, 0x2286, 0x2208, 0x2209,
255     0x2220, 0x2207, 0xf6da, 0xf6d9, 0xf6db, 0x220f, 0x221a, 0x22c5,
256     0x00ac, 0x2227, 0x2228, 0x21d4, 0x21d0, 0x21d1, 0x21d2, 0x21d3,
257     0x25ca, 0x2329, 0xf8e8, 0xf8e9, 0xf8ea, 0x2211, 0xf8eb, 0xf8ec,
258     0xf8ed, 0xf8ee, 0xf8ef, 0xf8f0, 0xf8f1, 0xf8f2, 0xf8f3, 0xf8f4,
259     0x0000, 0x232a, 0x222b, 0x2320, 0xf8f5, 0x2321, 0xf8f6, 0xf8f7,
260     0xf8f8, 0xf8f9, 0xf8fa, 0xf8fb, 0xf8fc, 0xf8fd, 0xf8fe, 0x0000,
261 };
262
263 // ---------------------------- PS/PDF helper methods -----------------------------------
264
265 QByteArray QFontSubset::glyphName(unsigned short unicode, bool symbol)
266 {
267     if (symbol && unicode < 0x100)
268         // map from latin1 to symbol
269         unicode = symbol_map[unicode];
270
271     int l = 0;
272     while(unicode_to_aglindex[l].u < unicode)
273         l++;
274     if (unicode_to_aglindex[l].u == unicode)
275         return agl + unicode_to_aglindex[l].index;
276
277     char buffer[8];
278     buffer[0] = 'u';
279     buffer[1] = 'n';
280     buffer[2] = 'i';
281     QPdf::toHex(unicode, buffer+3);
282     return buffer;
283 }
284
285 #ifndef QT_NO_FREETYPE
286 static FT_Face ft_face(const QFontEngine *engine)
287 {
288 #ifdef Q_WS_X11
289 #ifndef QT_NO_FONTCONFIG
290     if (engine->type() == QFontEngine::Freetype) {
291         const QFontEngineFT *ft = static_cast<const QFontEngineFT *>(engine);
292         return ft->non_locked_face();
293     } else
294 #endif
295     if (engine->type() == QFontEngine::XLFD) {
296         const QFontEngineXLFD *xlfd = static_cast<const QFontEngineXLFD *>(engine);
297         return xlfd->non_locked_face();
298     }
299 #endif
300 #ifdef Q_WS_QWS
301     if (engine->type() == QFontEngine::Freetype) {
302         const QFontEngineFT *ft = static_cast<const QFontEngineFT *>(engine);
303         return ft->non_locked_face();
304     }
305 #endif
306     return 0;
307 }
308 #endif
309
310 QByteArray QFontSubset::glyphName(unsigned int glyph, const QVector<int> reverseMap) const
311 {
312     uint glyphIndex = glyph_indices[glyph];
313
314     if (glyphIndex == 0)
315         return "/.notdef";
316
317     QByteArray ba;
318     QPdf::ByteStream s(&ba);
319 #ifndef QT_NO_FREETYPE
320     FT_Face face = ft_face(fontEngine);
321
322     char name[32];
323     name[0] = 0;
324     if (face && FT_HAS_GLYPH_NAMES(face)) {
325 #if defined(Q_WS_X11)
326         if (fontEngine->type() == QFontEngine::XLFD)
327             glyphIndex = static_cast<QFontEngineXLFD *>(fontEngine)->glyphIndexToFreetypeGlyphIndex(glyphIndex);
328 #endif
329         FT_Get_Glyph_Name(face, glyphIndex, &name, 32);
330         if (name[0] == '.') // fix broken PS fonts returning .notdef for many glyphs
331             name[0] = 0;
332     }
333     if (name[0]) {
334         s << '/' << name;
335     } else
336 #endif
337 #if defined(Q_WS_X11)
338     if (fontEngine->type() == QFontEngine::XLFD) {
339         uint uc = static_cast<QFontEngineXLFD *>(fontEngine)->toUnicode(glyphIndex);
340         s << '/' << glyphName(uc, false /* ### */);
341     } else
342 #endif
343     if (reverseMap[glyphIndex] && reverseMap[glyphIndex] < 0x10000) {
344         s << '/' << glyphName(reverseMap[glyphIndex], false);
345     } else {
346         s << "/gl" << (int)glyphIndex;
347     }
348     return ba;
349 }
350
351
352 QByteArray QFontSubset::widthArray() const
353 {
354     Q_ASSERT(!widths.isEmpty());
355
356     QFontEngine::Properties properties = fontEngine->properties();
357
358     QByteArray width;
359     QPdf::ByteStream s(&width);
360     QFixed scale = QFixed(1000)/emSquare;
361
362     QFixed defWidth = widths[0];
363     //qDebug("defWidth=%d, scale=%f", defWidth.toInt(), scale.toReal());
364     for (int i = 0; i < nGlyphs(); ++i) {
365         if (defWidth != widths[i])
366             defWidth = 0;
367     }
368     if (defWidth > 0) {
369         s << "/DW " << (defWidth*scale).toInt();
370     } else {
371         s << "/W [";
372         for (int g = 0; g < nGlyphs();) {
373             QFixed w = widths[g];
374             int start = g;
375             int startLinear = 0;
376             ++g;
377             while (g < nGlyphs()) {
378                 QFixed nw = widths[g];
379                 if (nw == w) {
380                 if (!startLinear)
381                     startLinear = g - 1;
382                 } else {
383                     if (startLinear > 0 && g - startLinear >= 10)
384                         break;
385                     startLinear = 0;
386                 }
387                 w = nw;
388                 ++g;
389             }
390             // qDebug("start=%x startLinear=%x g-1=%x",start,startLinear,g-1);
391             if (g - startLinear < 10)
392                 startLinear = 0;
393             int endnonlinear = startLinear ? startLinear : g;
394             // qDebug("    startLinear=%x endnonlinear=%x", startLinear,endnonlinear);
395             if (endnonlinear > start) {
396                 s << start << '[';
397                 for (int i = start; i < endnonlinear; ++i)
398                     s << (widths[i]*scale).toInt();
399                 s << "]\n";
400             }
401             if (startLinear)
402                 s << startLinear << g - 1 << (widths[startLinear]*scale).toInt() << '\n';
403         }
404         s << "]\n";
405     }
406     return width;
407 }
408
409 static void checkRanges(QPdf::ByteStream &ts, QByteArray &ranges, int &nranges)
410 {
411     if (++nranges > 100) {
412         ts << nranges << "beginbfrange\n"
413            << ranges << "endbfrange\n";
414         ranges = QByteArray();
415         nranges = 0;
416     }
417 }
418
419 QVector<int> QFontSubset::getReverseMap() const
420 {
421     QVector<int> reverseMap;
422     reverseMap.resize(0x10000);
423     for (uint i = 0; i < 0x10000; ++i)
424         reverseMap[i] = 0;
425     QGlyphLayoutArray<10> glyphs;
426     for (uint uc = 0; uc < 0x10000; ++uc) {
427         QChar ch(uc);
428         int nglyphs = 10;
429         fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly);
430         int idx = glyph_indices.indexOf(glyphs.glyphs[0]);
431         if (idx >= 0 && !reverseMap.at(idx))
432             reverseMap[idx] = uc;
433     }
434     return reverseMap;
435 }
436
437 QByteArray QFontSubset::createToUnicodeMap() const
438 {
439     QVector<int> reverseMap = getReverseMap();
440
441     QByteArray touc;
442     QPdf::ByteStream ts(&touc);
443     ts << "/CIDInit /ProcSet findresource begin\n"
444         "12 dict begin\n"
445         "begincmap\n"
446         "/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def\n"
447         "/CMapName /Adobe-Identity-UCS def\n"
448         "/CMapType 2 def\n"
449         "1 begincodespacerange\n"
450         "<0000> <FFFF>\n"
451         "endcodespacerange\n";
452
453     int nranges = 1;
454     QByteArray ranges = "<0000> <0000> <0000>\n";
455     QPdf::ByteStream s(&ranges);
456
457     char buf[5];
458     for (int g = 1; g < nGlyphs(); ) {
459         int uc0 = reverseMap.at(g);
460         if (!uc0) {
461             ++g;
462             continue;
463         }
464         int start = g;
465         int startLinear = 0;
466         ++g;
467         while (g < nGlyphs()) {
468             int uc = reverseMap[g];
469             // cmaps can't have the high byte changing within one range, so we need to break on that as well
470             if (!uc || (g>>8) != (start >> 8))
471                 break;
472             if (uc == uc0 + 1) {
473                 if (!startLinear)
474                     startLinear = g - 1;
475             } else {
476                 if (startLinear > 0 && g - startLinear >= 10)
477                     break;
478                 startLinear = 0;
479             }
480             uc0 = uc;
481             ++g;
482         }
483         // qDebug("start=%x startLinear=%x g-1=%x",start,startLinear,g-1);
484         if (g - startLinear < 10)
485             startLinear = 0;
486         int endnonlinear = startLinear ? startLinear : g;
487         // qDebug("    startLinear=%x endnonlinear=%x", startLinear,endnonlinear);
488         if (endnonlinear > start) {
489             s << '<' << QPdf::toHex((ushort)start, buf) << "> <";
490             s << QPdf::toHex((ushort)(endnonlinear - 1), buf) << "> ";
491             if (endnonlinear == start + 1) {
492                 s << '<' << QPdf::toHex((ushort)reverseMap[start], buf) << ">\n";
493             } else {
494                 s << '[';
495                 for (int i = start; i < endnonlinear; ++i) {
496                     s << '<' << QPdf::toHex((ushort)reverseMap[i], buf) << "> ";
497                 }
498                 s << "]\n";
499             }
500             checkRanges(ts, ranges, nranges);
501         }
502         if (startLinear) {
503             while (startLinear < g) {
504                 int len = g - startLinear;
505                 int uc_start = reverseMap[startLinear];
506                 int uc_end = uc_start + len - 1;
507                 if ((uc_end >> 8) != (uc_start >> 8))
508                     len = 256 - (uc_start & 0xff);
509                 s << '<' << QPdf::toHex((ushort)startLinear, buf) << "> <";
510                 s << QPdf::toHex((ushort)(startLinear + len - 1), buf) << "> ";
511                 s << '<' << QPdf::toHex((ushort)reverseMap[startLinear], buf) << ">\n";
512                 checkRanges(ts, ranges, nranges);
513                 startLinear += len;
514             }
515         }
516     }
517     if (nranges) {
518         ts << nranges << "beginbfrange\n"
519            << ranges << "endbfrange\n";
520     }
521     ts << "endcmap\n"
522         "CMapName currentdict /CMap defineresource pop\n"
523         "end\n"
524         "end\n";
525
526     return touc;
527 }
528
529 int QFontSubset::addGlyph(int index)
530 {
531     int idx = glyph_indices.indexOf(index);
532     if (idx < 0) {
533         idx = glyph_indices.size();
534         glyph_indices.append(index);
535     }
536     return idx;
537 }
538
539
540 // ------------------------------ Truetype generation ----------------------------------------------
541
542 typedef qint16 F2DOT14;
543 typedef quint32 Tag;
544 typedef quint16 GlyphID;
545 typedef quint16 Offset;
546
547
548 class QTtfStream {
549 public:
550     QTtfStream(QByteArray &ba) : data((uchar *)ba.data()) { start = data; }
551     QTtfStream &operator <<(quint8 v) { *data = v; ++data; return *this; }
552     QTtfStream &operator <<(quint16 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
553     QTtfStream &operator <<(quint32 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
554     QTtfStream &operator <<(qint8 v) { *data = quint8(v); ++data; return *this; }
555     QTtfStream &operator <<(qint16 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
556     QTtfStream &operator <<(qint32 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
557     QTtfStream &operator <<(qint64 v) { qToBigEndian(v, data); data += sizeof(v); return *this; }
558
559     int offset() const { return data - start; }
560     void setOffset(int o) { data = start + o; }
561     void align4() { while (offset() & 3) { *data = '\0'; ++data; } }
562 private:
563     uchar *data;
564     uchar *start;
565 };
566
567 struct QTtfTable {
568     Tag tag;
569     QByteArray data;
570 };
571 Q_DECLARE_TYPEINFO(QTtfTable, Q_MOVABLE_TYPE);
572
573
574 struct qttf_head_table {
575     qint32 font_revision;
576     quint16 flags;
577     qint64 created;
578     qint64 modified;
579     qint16 xMin;
580     qint16 yMin;
581     qint16 xMax;
582     qint16 yMax;
583     quint16 macStyle;
584     qint16 indexToLocFormat;
585 };
586
587
588 struct qttf_hhea_table {
589     qint16 ascender;
590     qint16 descender;
591     qint16 lineGap;
592     quint16 maxAdvanceWidth;
593     qint16 minLeftSideBearing;
594     qint16 minRightSideBearing;
595     qint16 xMaxExtent;
596     quint16 numberOfHMetrics;
597 };
598
599
600 struct qttf_maxp_table {
601     quint16 numGlyphs;
602     quint16 maxPoints;
603     quint16 maxContours;
604     quint16 maxCompositePoints;
605     quint16 maxCompositeContours;
606     quint16 maxComponentElements;
607     quint16 maxComponentDepth;
608 };
609
610 struct qttf_name_table {
611     QString copyright;
612     QString family;
613     QString subfamily;
614     QString postscript_name;
615 };
616
617
618 static QTtfTable generateHead(const qttf_head_table &head);
619 static QTtfTable generateHhea(const qttf_hhea_table &hhea);
620 static QTtfTable generateMaxp(const qttf_maxp_table &maxp);
621 static QTtfTable generateName(const qttf_name_table &name);
622
623 struct qttf_font_tables
624 {
625     qttf_head_table head;
626     qttf_hhea_table hhea;
627     qttf_maxp_table maxp;
628 };
629
630
631 struct QTtfGlyph {
632     quint16 index;
633     qint16 xMin;
634     qint16 xMax;
635     qint16 yMin;
636     qint16 yMax;
637     quint16 advanceWidth;
638     qint16 lsb;
639     quint16 numContours;
640     quint16 numPoints;
641     QByteArray data;
642 };
643 Q_DECLARE_TYPEINFO(QTtfGlyph, Q_MOVABLE_TYPE);
644
645 static QTtfGlyph generateGlyph(int index, const QPainterPath &path, qreal advance, qreal lsb, qreal ppem);
646 // generates glyf, loca and hmtx
647 static QList<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QList<QTtfGlyph> &_glyphs);
648
649 static QByteArray bindFont(const QList<QTtfTable>& _tables);
650
651
652 static quint32 checksum(const QByteArray &table)
653 {
654     quint32 sum = 0;
655     int offset = 0;
656     const uchar *d = (uchar *)table.constData();
657     while (offset <= table.size()-3) {
658         sum += qFromBigEndian<quint32>(d + offset);
659         offset += 4;
660     }
661     int shift = 24;
662     quint32 x = 0;
663     while (offset < table.size()) {
664         x |= ((quint32)d[offset]) << shift;
665         ++offset;
666         shift -= 8;
667     }
668     sum += x;
669
670     return sum;
671 }
672
673 static QTtfTable generateHead(const qttf_head_table &head)
674 {
675     const int head_size = 54;
676     QTtfTable t;
677     t.tag = MAKE_TAG('h', 'e', 'a', 'd');
678     t.data.resize(head_size);
679
680     QTtfStream s(t.data);
681
682 // qint32  Table version number  0x00010000 for version 1.0.
683 // qint32  fontRevision  Set by font manufacturer.
684     s << qint32(0x00010000)
685       << head.font_revision
686 // quint32  checkSumAdjustment  To compute: set it to 0, sum the entire font as quint32, then store 0xB1B0AFBA - sum.
687       << quint32(0)
688 // quint32  magicNumber  Set to 0x5F0F3CF5.
689       << quint32(0x5F0F3CF5)
690 // quint16  flags  Bit 0: Baseline for font at y=0;
691 // Bit 1: Left sidebearing point at x=0;
692 // Bit 2: Instructions may depend on point size;
693 // Bit 3: Force ppem to integer values for all internal scaler math; may use fractional ppem sizes if this bit is clear;
694 // Bit 4: Instructions may alter advance width (the advance widths might not scale linearly);
695 // Bits 5-10: These should be set according to  Apple's specification . However, they are not implemented in OpenType.
696 // Bit 11: Font data is 'lossless,' as a result of having been compressed and decompressed with the Agfa MicroType Express engine.
697 // Bit 12: Font converted (produce compatible metrics)
698 // Bit 13: Font optimized for ClearType
699 // Bit 14: Reserved, set to 0
700 // Bit 15: Reserved, set to 0
701       << quint16(0)
702
703 // quint16  unitsPerEm  Valid range is from 16 to 16384. This value should be a power of 2 for fonts that have TrueType outlines.
704       << quint16(2048)
705 // qint64  created  Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer
706       << head.created
707 // qint64  modified  Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer
708       << head.modified
709 // qint16  xMin  For all glyph bounding boxes.
710 // qint16  yMin  For all glyph bounding boxes.
711 // qint16  xMax  For all glyph bounding boxes.
712 // qint16  yMax  For all glyph bounding boxes.
713       << head.xMin
714       << head.yMin
715       << head.xMax
716       << head.yMax
717 // quint16  macStyle  Bit 0: Bold (if set to 1);
718 // Bit 1: Italic (if set to 1)
719 // Bit 2: Underline (if set to 1)
720 // Bit 3: Outline (if set to 1)
721 // Bit 4: Shadow (if set to 1)
722 // Bit 5: Condensed (if set to 1)
723 // Bit 6: Extended (if set to 1)
724 // Bits 7-15: Reserved (set to 0).
725       << head.macStyle
726 // quint16  lowestRecPPEM  Smallest readable size in pixels.
727       << quint16(6) // just a wild guess
728 // qint16  fontDirectionHint   0: Fully mixed directional glyphs;
729       << qint16(0)
730 // 1: Only strongly left to right;
731 // 2: Like 1 but also contains neutrals;
732 // -1: Only strongly right to left;
733 // -2: Like -1 but also contains neutrals. 1
734 // qint16  indexToLocFormat  0 for short offsets, 1 for long.
735       << head.indexToLocFormat
736 // qint16  glyphDataFormat  0 for current format.
737       << qint16(0);
738
739     Q_ASSERT(s.offset() == head_size);
740     return t;
741 }
742
743
744 static QTtfTable generateHhea(const qttf_hhea_table &hhea)
745 {
746     const int hhea_size = 36;
747     QTtfTable t;
748     t.tag = MAKE_TAG('h', 'h', 'e', 'a');
749     t.data.resize(hhea_size);
750
751     QTtfStream s(t.data);
752 // qint32  Table version number  0x00010000 for version 1.0.
753     s << qint32(0x00010000)
754 // qint16  Ascender  Typographic ascent.  (Distance from baseline of highest ascender)
755       << hhea.ascender
756 // qint16  Descender  Typographic descent.  (Distance from baseline of lowest descender)
757       << hhea.descender
758 // qint16  LineGap  Typographic line gap.
759 // Negative LineGap values are treated as zero
760 // in Windows 3.1, System 6, and
761 // System 7.
762       << hhea.lineGap
763 // quint16  advanceWidthMax  Maximum advance width value in 'hmtx' table.
764       << hhea.maxAdvanceWidth
765 // qint16  minLeftSideBearing  Minimum left sidebearing value in 'hmtx' table.
766       << hhea.minLeftSideBearing
767 // qint16  minRightSideBearing  Minimum right sidebearing value; calculated as Min(aw - lsb - (xMax - xMin)).
768       << hhea.minRightSideBearing
769 // qint16  xMaxExtent  Max(lsb + (xMax - xMin)).
770       << hhea.xMaxExtent
771 // qint16  caretSlopeRise  Used to calculate the slope of the cursor (rise/run); 1 for vertical.
772       << qint16(1)
773 // qint16  caretSlopeRun  0 for vertical.
774       << qint16(0)
775 // 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
776       << qint16(0)
777 // qint16  (reserved)  set to 0
778       << qint16(0)
779 // qint16  (reserved)  set to 0
780       << qint16(0)
781 // qint16  (reserved)  set to 0
782       << qint16(0)
783 // qint16  (reserved)  set to 0
784       << qint16(0)
785 // qint16  metricDataFormat  0 for current format.
786       << qint16(0)
787 // quint16  numberOfHMetrics  Number of hMetric entries in 'hmtx' table
788       << hhea.numberOfHMetrics;
789
790     Q_ASSERT(s.offset() == hhea_size);
791     return t;
792 }
793
794
795 static QTtfTable generateMaxp(const qttf_maxp_table &maxp)
796 {
797     const int maxp_size = 32;
798     QTtfTable t;
799     t.tag = MAKE_TAG('m', 'a', 'x', 'p');
800     t.data.resize(maxp_size);
801
802     QTtfStream s(t.data);
803
804 // qint32  Table version number  0x00010000 for version 1.0.
805     s << qint32(0x00010000)
806 // quint16  numGlyphs  The number of glyphs in the font.
807       << maxp.numGlyphs
808 // quint16  maxPoints  Maximum points in a non-composite glyph.
809       << maxp.maxPoints
810 // quint16  maxContours  Maximum contours in a non-composite glyph.
811       << maxp.maxContours
812 // quint16  maxCompositePoints  Maximum points in a composite glyph.
813       << maxp.maxCompositePoints
814 // quint16  maxCompositeContours  Maximum contours in a composite glyph.
815       << maxp.maxCompositeContours
816 // 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.
817       << quint16(1) // we do not embed instructions
818 // quint16  maxTwilightPoints  Maximum points used in Z0.
819       << quint16(0)
820 // quint16  maxStorage  Number of Storage Area locations.
821       << quint16(0)
822 // quint16  maxFunctionDefs  Number of FDEFs.
823       << quint16(0)
824 // quint16  maxInstructionDefs  Number of IDEFs.
825       << quint16(0)
826 // quint16  maxStackElements  Maximum stack depth2.
827       << quint16(0)
828 // quint16  maxSizeOfInstructions  Maximum byte count for glyph instructions.
829       << quint16(0)
830 // quint16  maxComponentElements  Maximum number of components referenced at "top level" for any composite glyph.
831       << maxp.maxComponentElements
832 // quint16  maxComponentDepth  Maximum levels of recursion; 1 for simple components.
833       << maxp.maxComponentDepth;
834
835     Q_ASSERT(s.offset() == maxp_size);
836     return t;
837 }
838
839 struct QTtfNameRecord {
840     quint16 nameId;
841     QString value;
842 };
843
844 static QTtfTable generateName(const QList<QTtfNameRecord> &name);
845
846 static QTtfTable generateName(const qttf_name_table &name)
847 {
848     QList<QTtfNameRecord> list;
849     QTtfNameRecord rec;
850     rec.nameId = 0;
851     rec.value = name.copyright;
852     list.append(rec);
853     rec.nameId = 1;
854     rec.value = name.family;
855     list.append(rec);
856     rec.nameId = 2;
857     rec.value = name.subfamily;
858     list.append(rec);
859     rec.nameId = 4;
860     rec.value = name.family;
861     if (name.subfamily != QLatin1String("Regular"))
862         rec.value += QLatin1Char(' ') + name.subfamily;
863     list.append(rec);
864     rec.nameId = 6;
865     rec.value = name.postscript_name;
866     list.append(rec);
867
868     return generateName(list);
869 }
870
871 // ####### should probably generate Macintosh/Roman name entries as well
872 static QTtfTable generateName(const QList<QTtfNameRecord> &name)
873 {
874     const int char_size = 2;
875
876     QTtfTable t;
877     t.tag = MAKE_TAG('n', 'a', 'm', 'e');
878
879     const int name_size = 6 + 12*name.size();
880     int string_size = 0;
881     for (int i = 0; i < name.size(); ++i) {
882         string_size += name.at(i).value.length()*char_size;
883     }
884     t.data.resize(name_size + string_size);
885
886     QTtfStream s(t.data);
887 // quint16  format  Format selector (=0).
888     s << quint16(0)
889 // quint16  count  Number of name records.
890       << quint16(name.size())
891 // quint16  stringOffset  Offset to start of string storage (from start of table).
892       << quint16(name_size);
893 // NameRecord  nameRecord[count]  The name records where count is the number of records.
894 // (Variable)
895
896     int off = 0;
897     for (int i = 0; i < name.size(); ++i) {
898         int len = name.at(i).value.length()*char_size;
899 // quint16  platformID  Platform ID.
900 // quint16  encodingID  Platform-specific encoding ID.
901 // quint16  languageID  Language ID.
902         s << quint16(3)
903           << quint16(1)
904           << quint16(0x0409) // en_US
905 // quint16  nameId  Name ID.
906           << name.at(i).nameId
907 // quint16  length  String length (in bytes).
908           << quint16(len)
909 // quint16  offset  String offset from start of storage area (in bytes).
910           << quint16(off);
911         off += len;
912     }
913     for (int i = 0; i < name.size(); ++i) {
914         const QString &n = name.at(i).value;
915         const ushort *uc = n.utf16();
916         for (int i = 0; i < n.length(); ++i) {
917             s << quint16(*uc);
918             ++uc;
919         }
920     }
921     return t;
922 }
923
924
925 enum Flags {
926     OffCurve = 0,
927     OnCurve = (1 << 0),
928     XShortVector = (1 << 1),
929     YShortVector = (1 << 2),
930     Repeat = (1 << 3),
931     XSame = (1 << 4),
932     XShortPositive = (1 << 4),
933     YSame = (1 << 5),
934     YShortPositive = (1 << 5)
935 };
936 struct TTF_POINT {
937     qint16 x;
938     qint16 y;
939     quint8 flags;
940 };
941 Q_DECLARE_TYPEINFO(TTF_POINT, Q_PRIMITIVE_TYPE);
942
943 static void convertPath(const QPainterPath &path, QList<TTF_POINT> *points, QList<int> *endPoints, qreal ppem)
944 {
945     int numElements = path.elementCount();
946     for (int i = 0; i < numElements - 1; ++i) {
947         const QPainterPath::Element &e = path.elementAt(i);
948         TTF_POINT p;
949         p.x = qRound(e.x * 2048. / ppem);
950         p.y = qRound(-e.y * 2048. / ppem);
951         p.flags = 0;
952
953         switch(e.type) {
954         case QPainterPath::MoveToElement:
955             if (i != 0) {
956                 // see if start and end points of the last contour agree
957                 int start = endPoints->size() ? endPoints->at(endPoints->size()-1) - 1 : 0;
958                 int end = points->size() - 1;
959                 if (points->at(end).x == points->at(start).x
960                     && points->at(end).y == points->at(start).y)
961                     points->takeLast();
962                 endPoints->append(points->size() - 1);
963             }
964             // fall through
965         case QPainterPath::LineToElement:
966             p.flags = OnCurve;
967             break;
968         case QPainterPath::CurveToElement: {
969             // cubic bezier curve, we need to reduce to a list of quadratic curves
970             TTF_POINT list[3*16 + 4]; // we need max 16 subdivisions
971             list[3] = points->at(points->size() - 1);
972             list[2] = p;
973             const QPainterPath::Element &e2 = path.elementAt(++i);
974             list[1].x = qRound(e2.x * 2048. / ppem);
975             list[1].y = qRound(-e2.y * 2048. / ppem);
976             const QPainterPath::Element &e3 = path.elementAt(++i);
977             list[0].x = qRound(e3.x * 2048. / ppem);
978             list[0].y = qRound(-e3.y * 2048. / ppem);
979
980             TTF_POINT *base = list;
981
982             bool try_reduce = points->size() > 1
983                               && points->at(points->size() - 1).flags == OnCurve
984                               && points->at(points->size() - 2).flags == OffCurve;
985 //             qDebug("generating beziers:");
986             while (base >= list) {
987                 const int split_limit = 3;
988 //                 {
989 //                     qDebug("iteration:");
990 //                     TTF_POINT *x = list;
991 //                     while (x <= base + 3) {
992 //                         qDebug() << "    " << QPoint(x->x, x->y);
993 //                         ++x;
994 //                     }
995 //                 }
996                 Q_ASSERT(base - list < 3*16 + 1);
997                 // first see if we can easily reduce the cubic to a quadratic bezier curve
998                 int i1_x = base[1].x + ((base[1].x - base[0].x) >> 1);
999                 int i1_y = base[1].y + ((base[1].y - base[0].y) >> 1);
1000                 int i2_x = base[2].x + ((base[2].x - base[3].x) >> 1);
1001                 int i2_y = base[2].y + ((base[2].y - base[3].y) >> 1);
1002 //                 qDebug() << "checking: i1=" << QPoint(i1_x, i1_y) << " i2=" << QPoint(i2_x, i2_y);
1003                 if (qAbs(i1_x - i2_x) <= split_limit && qAbs(i1_y - i2_y) <= split_limit) {
1004                     // got a quadratic bezier curve
1005                     TTF_POINT np;
1006                     np.x = (i1_x + i2_x) >> 1;
1007                     np.y = (i1_y + i2_y) >> 1;
1008                     if (try_reduce) {
1009                         // see if we can optimize out the last onCurve point
1010                         int mx = (points->at(points->size() - 2).x + base[2].x) >> 1;
1011                         int my = (points->at(points->size() - 2).y + base[2].y) >> 1;
1012                         if (qAbs(mx - base[3].x) <= split_limit && qAbs(my = base[3].y) <= split_limit)
1013                             points->takeLast();
1014                         try_reduce = false;
1015                     }
1016                     np.flags = OffCurve;
1017                     points->append(np);
1018 //                     qDebug() << "   appending offcurve point " << QPoint(np.x, np.y);
1019                     base -= 3;
1020                 } else {
1021                     // need to split
1022 //                     qDebug() << "  -> splitting";
1023                     qint16 a, b, c, d;
1024                     base[6].x = base[3].x;
1025                     c = base[1].x;
1026                     d = base[2].x;
1027                     base[1].x = a = ( base[0].x + c ) >> 1;
1028                     base[5].x = b = ( base[3].x + d ) >> 1;
1029                     c = ( c + d ) >> 1;
1030                     base[2].x = a = ( a + c ) >> 1;
1031                     base[4].x = b = ( b + c ) >> 1;
1032                     base[3].x = ( a + b ) >> 1;
1033
1034                     base[6].y = base[3].y;
1035                     c = base[1].y;
1036                     d = base[2].y;
1037                     base[1].y = a = ( base[0].y + c ) >> 1;
1038                     base[5].y = b = ( base[3].y + d ) >> 1;
1039                     c = ( c + d ) >> 1;
1040                     base[2].y = a = ( a + c ) >> 1;
1041                     base[4].y = b = ( b + c ) >> 1;
1042                     base[3].y = ( a + b ) >> 1;
1043                     base += 3;
1044                 }
1045             }
1046             p = list[0];
1047             p.flags = OnCurve;
1048             break;
1049         }
1050         case QPainterPath::CurveToDataElement:
1051             Q_ASSERT(false);
1052             break;
1053         }
1054 //         qDebug() << "   appending oncurve point " << QPoint(p.x, p.y);
1055         points->append(p);
1056     }
1057     int start = endPoints->size() ? endPoints->at(endPoints->size()-1) + 1 : 0;
1058     int end = points->size() - 1;
1059     if (points->at(end).x == points->at(start).x
1060         && points->at(end).y == points->at(start).y)
1061         points->takeLast();
1062     endPoints->append(points->size() - 1);
1063 }
1064
1065 static void getBounds(const QList<TTF_POINT> &points, qint16 *xmin, qint16 *xmax, qint16 *ymin, qint16 *ymax)
1066 {
1067     *xmin = points.at(0).x;
1068     *xmax = *xmin;
1069     *ymin = points.at(0).y;
1070     *ymax = *ymin;
1071
1072     for (int i = 1; i < points.size(); ++i) {
1073         *xmin = qMin(*xmin, points.at(i).x);
1074         *xmax = qMax(*xmax, points.at(i).x);
1075         *ymin = qMin(*ymin, points.at(i).y);
1076         *ymax = qMax(*ymax, points.at(i).y);
1077     }
1078 }
1079
1080 static int convertToRelative(QList<TTF_POINT> *points)
1081 {
1082     // convert points to relative and setup flags
1083 //     qDebug() << "relative points:";
1084     qint16 prev_x = 0;
1085     qint16 prev_y = 0;
1086     int point_array_size = 0;
1087     for (int i = 0; i < points->size(); ++i) {
1088         const int x = points->at(i).x;
1089         const int y = points->at(i).y;
1090         TTF_POINT rel;
1091         rel.x = x - prev_x;
1092         rel.y = y - prev_y;
1093         rel.flags = points->at(i).flags;
1094         Q_ASSERT(rel.flags < 2);
1095         if (!rel.x) {
1096             rel.flags |= XSame;
1097         } else if (rel.x > 0 && rel.x < 256) {
1098             rel.flags |= XShortVector|XShortPositive;
1099             point_array_size++;
1100         } else if (rel.x < 0 && rel.x > -256) {
1101             rel.flags |= XShortVector;
1102             rel.x = -rel.x;
1103             point_array_size++;
1104         } else {
1105             point_array_size += 2;
1106         }
1107         if (!rel.y) {
1108             rel.flags |= YSame;
1109         } else if (rel.y > 0 && rel.y < 256) {
1110             rel.flags |= YShortVector|YShortPositive;
1111             point_array_size++;
1112         } else if (rel.y < 0 && rel.y > -256) {
1113             rel.flags |= YShortVector;
1114             rel.y = -rel.y;
1115             point_array_size++;
1116         } else {
1117             point_array_size += 2;
1118         }
1119         (*points)[i] = rel;
1120 // #define toString(x) ((rel.flags & x) ? #x : "")
1121 //         qDebug() << "    " << QPoint(rel.x, rel.y) << "flags="
1122 //                  << toString(OnCurve) << toString(XShortVector)
1123 //                  << (rel.flags & XShortVector ? toString(XShortPositive) : toString(XSame))
1124 //                  << toString(YShortVector)
1125 //                  << (rel.flags & YShortVector ? toString(YShortPositive) : toString(YSame));
1126
1127         prev_x = x;
1128         prev_y = y;
1129     }
1130     return point_array_size;
1131 }
1132
1133 static void getGlyphData(QTtfGlyph *glyph, const QList<TTF_POINT> &points, const QList<int> &endPoints, int point_array_size)
1134 {
1135     const int max_size = 5*sizeof(qint16) // header
1136                          + endPoints.size()*sizeof(quint16) // end points of contours
1137                          + sizeof(quint16) // instruction length == 0
1138                          + points.size()*(1) // flags
1139                          + point_array_size; // coordinates
1140
1141     glyph->data.resize(max_size);
1142
1143     QTtfStream s(glyph->data);
1144     s << qint16(endPoints.size())
1145       << glyph->xMin << glyph->yMin << glyph->xMax << glyph->yMax;
1146
1147     for (int i = 0; i < endPoints.size(); ++i)
1148         s << quint16(endPoints.at(i));
1149     s << quint16(0); // instruction length
1150
1151     // emit flags
1152     for (int i = 0; i < points.size(); ++i)
1153         s << quint8(points.at(i).flags);
1154     // emit points
1155     for (int i = 0; i < points.size(); ++i) {
1156         quint8 flags = points.at(i).flags;
1157         qint16 x = points.at(i).x;
1158
1159         if (flags & XShortVector)
1160             s << quint8(x);
1161         else if (!(flags & XSame))
1162             s << qint16(x);
1163     }
1164     for (int i = 0; i < points.size(); ++i) {
1165         quint8 flags = points.at(i).flags;
1166         qint16 y = points.at(i).y;
1167
1168         if (flags & YShortVector)
1169             s << quint8(y);
1170         else if (!(flags & YSame))
1171             s << qint16(y);
1172     }
1173
1174 //     qDebug() << "offset=" << s.offset() << "max_size=" << max_size << "point_array_size=" << point_array_size;
1175     Q_ASSERT(s.offset() == max_size);
1176
1177     glyph->numContours = endPoints.size();
1178     glyph->numPoints = points.size();
1179 }
1180
1181 static QTtfGlyph generateGlyph(int index, const QPainterPath &path, qreal advance, qreal lsb, qreal ppem)
1182 {
1183     QList<TTF_POINT> points;
1184     QList<int> endPoints;
1185     QTtfGlyph glyph;
1186     glyph.index = index;
1187     glyph.advanceWidth = qRound(advance * 2048. / ppem);
1188     glyph.lsb = qRound(lsb * 2048. / ppem);
1189
1190     if (!path.elementCount()) {
1191         //qDebug("glyph %d is empty", index);
1192         lsb = 0;
1193         glyph.xMin = glyph.xMax = glyph.yMin = glyph.yMax = 0;
1194         glyph.numContours = 0;
1195         glyph.numPoints = 0;
1196         return glyph;
1197     }
1198
1199     convertPath(path, &points, &endPoints, ppem);
1200
1201 //     qDebug() << "number of contours=" << endPoints.size();
1202 //     for (int i = 0; i < points.size(); ++i)
1203 //         qDebug() << "  point[" << i << "] = " << QPoint(points.at(i).x, points.at(i).y) << " flags=" << points.at(i).flags;
1204 //     qDebug() << "endPoints:";
1205 //     for (int i = 0; i < endPoints.size(); ++i)
1206 //         qDebug() << endPoints.at(i);
1207
1208     getBounds(points, &glyph.xMin, &glyph.xMax, &glyph.yMin, &glyph.yMax);
1209     int point_array_size = convertToRelative(&points);
1210     getGlyphData(&glyph, points, endPoints, point_array_size);
1211     return glyph;
1212 }
1213
1214 Q_STATIC_GLOBAL_OPERATOR bool operator <(const QTtfGlyph &g1, const QTtfGlyph &g2)
1215 {
1216     return g1.index < g2.index;
1217 }
1218
1219 static QList<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QList<QTtfGlyph> &_glyphs)
1220 {
1221     const int max_size_small = 65536*2;
1222     QList<QTtfGlyph> glyphs = _glyphs;
1223     qSort(glyphs);
1224
1225     Q_ASSERT(tables.maxp.numGlyphs == glyphs.at(glyphs.size()-1).index + 1);
1226     int nGlyphs = tables.maxp.numGlyphs;
1227
1228     int glyf_size = 0;
1229     for (int i = 0; i < glyphs.size(); ++i)
1230         glyf_size += (glyphs.at(i).data.size() + 3) & ~3;
1231
1232     tables.head.indexToLocFormat = glyf_size < max_size_small ? 0 : 1;
1233     tables.hhea.numberOfHMetrics = nGlyphs;
1234
1235     QTtfTable glyf;
1236     glyf.tag = MAKE_TAG('g', 'l', 'y', 'f');
1237
1238     QTtfTable loca;
1239     loca.tag = MAKE_TAG('l', 'o', 'c', 'a');
1240     loca.data.resize(glyf_size < max_size_small ? (nGlyphs+1)*sizeof(quint16) : (nGlyphs+1)*sizeof(quint32));
1241     QTtfStream ls(loca.data);
1242
1243     QTtfTable hmtx;
1244     hmtx.tag = MAKE_TAG('h', 'm', 't', 'x');
1245     hmtx.data.resize(nGlyphs*4);
1246     QTtfStream hs(hmtx.data);
1247
1248     int pos = 0;
1249     for (int i = 0; i < nGlyphs; ++i) {
1250         int gpos = glyf.data.size();
1251         quint16 advance = 0;
1252         qint16 lsb = 0;
1253
1254         if (glyphs[pos].index == i) {
1255             // emit glyph
1256 //             qDebug("emitting glyph %d: size=%d", i, glyphs.at(i).data.size());
1257             glyf.data += glyphs.at(pos).data;
1258             while (glyf.data.size() & 1)
1259                 glyf.data.append('\0');
1260             advance = glyphs.at(pos).advanceWidth;
1261             lsb = glyphs.at(pos).lsb;
1262             ++pos;
1263         }
1264         if (glyf_size < max_size_small) {
1265             // use short loca format
1266             ls << quint16(gpos>>1);
1267         } else {
1268             // use long loca format
1269             ls << quint32(gpos);
1270         }
1271         hs << advance
1272            << lsb;
1273     }
1274     if (glyf_size < max_size_small) {
1275         // use short loca format
1276         ls << quint16(glyf.data.size()>>1);
1277     } else {
1278         // use long loca format
1279         ls << quint32(glyf.data.size());
1280     }
1281
1282     Q_ASSERT(loca.data.size() == ls.offset());
1283     Q_ASSERT(hmtx.data.size() == hs.offset());
1284
1285     QList<QTtfTable> list;
1286     list.append(glyf);
1287     list.append(loca);
1288     list.append(hmtx);
1289     return list;
1290 }
1291
1292 Q_STATIC_GLOBAL_OPERATOR bool operator <(const QTtfTable &t1, const QTtfTable &t2)
1293 {
1294     return t1.tag < t2.tag;
1295 }
1296
1297 static QByteArray bindFont(const QList<QTtfTable>& _tables)
1298 {
1299     QList<QTtfTable> tables = _tables;
1300
1301     qSort(tables);
1302
1303     QByteArray font;
1304     const int header_size = sizeof(qint32) + 4*sizeof(quint16);
1305     const int directory_size = 4*sizeof(quint32)*tables.size();
1306     font.resize(header_size + directory_size);
1307
1308     int log2 = 0;
1309     int pow = 1;
1310     int n = tables.size() >> 1;
1311     while (n) {
1312         ++log2;
1313         pow <<= 1;
1314         n >>= 1;
1315     }
1316
1317     quint32 head_offset = 0;
1318     {
1319         QTtfStream f(font);
1320 // Offset Table
1321 // Type  Name  Description
1322 //   qint32  sfnt version  0x00010000 for version 1.0.
1323 //   quint16   numTables  Number of tables.
1324 //   quint16   searchRange  (Maximum power of 2 <= numTables) x 16.
1325 //   quint16   entrySelector  Log2(maximum power of 2 <= numTables).
1326 //   quint16   rangeShift  NumTables x 16-searchRange.
1327         f << qint32(0x00010000)
1328           << quint16(tables.size())
1329           << quint16(16*pow)
1330           << quint16(log2)
1331           << quint16(16*(tables.size() - pow));
1332
1333 // Table Directory
1334 // Type  Name  Description
1335 //   quint32  tag  4 -byte identifier.
1336 //   quint32  checkSum  CheckSum for this table.
1337 //   quint32  offset  Offset from beginning of TrueType font file.
1338 //   quint32  length  Length of this table.
1339         quint32 table_offset = header_size + directory_size;
1340         for (int i = 0; i < tables.size(); ++i) {
1341             const QTtfTable &t = tables.at(i);
1342             const quint32 size = (t.data.size() + 3) & ~3;
1343             if (t.tag == MAKE_TAG('h', 'e', 'a', 'd'))
1344                 head_offset = table_offset;
1345             f << t.tag
1346               << checksum(t.data)
1347               << table_offset
1348               << t.data.size();
1349             table_offset += size;
1350 #define TAG(x) char(t.tag >> 24) << char((t.tag >> 16) & 0xff) << char((t.tag >> 8) & 0xff) << char(t.tag & 0xff)
1351             //qDebug() << "table " << TAG(t.tag) << "has size " << t.data.size() << "stream at " << f.offset();
1352         }
1353     }
1354     for (int i = 0; i < tables.size(); ++i) {
1355         const QByteArray &t = tables.at(i).data;
1356         font += t;
1357         int s = t.size();
1358         while (s & 3) { font += '\0'; ++s; }
1359     }
1360
1361     if (!head_offset) {
1362         qWarning("QFontSubset: Font misses 'head' table");
1363         return QByteArray();
1364     }
1365
1366     // calculate the fonts checksum and qToBigEndian into 'head's checksum_adjust
1367     quint32 checksum_adjust = 0xB1B0AFBA - checksum(font);
1368     qToBigEndian(checksum_adjust, (uchar *)font.data() + head_offset + 8);
1369
1370     return font;
1371 }
1372
1373
1374 /*
1375   PDF requires the following tables:
1376
1377   head, hhea, loca, maxp, cvt , prep, glyf, hmtx, fpgm
1378
1379   This means we don't have to add a os/2, post or name table. cvt , prep and fpgm could be empty
1380   if really required.
1381 */
1382
1383 QByteArray QFontSubset::toTruetype() const
1384 {
1385     qttf_font_tables font;
1386     memset(&font, 0, sizeof(qttf_font_tables));
1387
1388     qreal ppem = fontEngine->fontDef.pixelSize;
1389 #define TO_TTF(x) qRound(x * 2048. / ppem)
1390     QList<QTtfGlyph> glyphs;
1391
1392     QFontEngine::Properties properties = fontEngine->properties();
1393     // initialize some stuff needed in createWidthArray
1394     emSquare = 2048;
1395     widths.resize(nGlyphs());
1396
1397     // head table
1398     font.head.font_revision = 0x00010000;
1399     font.head.flags = (1 << 2) | (1 << 4);
1400     font.head.created = 0; // ###
1401     font.head.modified = 0; // ###
1402     font.head.xMin = SHRT_MAX;
1403     font.head.xMax = SHRT_MIN;
1404     font.head.yMin = SHRT_MAX;
1405     font.head.yMax = SHRT_MIN;
1406     font.head.macStyle = (fontEngine->fontDef.weight > QFont::Normal) ? 1 : 0;
1407     font.head.macStyle |= (fontEngine->fontDef.styleHint != QFont::StyleNormal) ? 1 : 0;
1408
1409     // hhea table
1410     font.hhea.ascender = qRound(properties.ascent);
1411     font.hhea.descender = -qRound(properties.descent);
1412     font.hhea.lineGap = qRound(properties.leading);
1413     font.hhea.maxAdvanceWidth = TO_TTF(fontEngine->maxCharWidth());
1414     font.hhea.minLeftSideBearing = TO_TTF(fontEngine->minLeftBearing());
1415     font.hhea.minRightSideBearing = TO_TTF(fontEngine->minRightBearing());
1416     font.hhea.xMaxExtent = SHRT_MIN;
1417
1418     font.maxp.numGlyphs = 0;
1419     font.maxp.maxPoints = 0;
1420     font.maxp.maxContours = 0;
1421     font.maxp.maxCompositePoints = 0;
1422     font.maxp.maxCompositeContours = 0;
1423     font.maxp.maxComponentElements = 0;
1424     font.maxp.maxComponentDepth = 0;
1425     font.maxp.numGlyphs = nGlyphs();
1426
1427
1428
1429     uint sumAdvances = 0;
1430     for (int i = 0; i < nGlyphs(); ++i) {
1431         glyph_t g = glyph_indices.at(i);
1432         QPainterPath path;
1433         glyph_metrics_t metric;
1434         fontEngine->getUnscaledGlyph(g, &path, &metric);
1435         if (noEmbed) {
1436             path = QPainterPath();
1437             if (g == 0)
1438                 path.addRect(QRectF(0, 0, 1000, 1000));
1439         }
1440         QTtfGlyph glyph = generateGlyph(i, path, metric.xoff.toReal(), metric.x.toReal(), properties.emSquare.toReal());
1441
1442         font.head.xMin = qMin(font.head.xMin, glyph.xMin);
1443         font.head.xMax = qMax(font.head.xMax, glyph.xMax);
1444         font.head.yMin = qMin(font.head.yMin, glyph.yMin);
1445         font.head.yMax = qMax(font.head.yMax, glyph.yMax);
1446
1447         font.hhea.xMaxExtent = qMax(font.hhea.xMaxExtent, (qint16)(glyph.lsb + glyph.xMax - glyph.xMin));
1448
1449         font.maxp.maxPoints = qMax(font.maxp.maxPoints, glyph.numPoints);
1450         font.maxp.maxContours = qMax(font.maxp.maxContours, glyph.numContours);
1451
1452         if (glyph.xMax > glyph.xMin)
1453             sumAdvances += glyph.xMax - glyph.xMin;
1454
1455 //         qDebug("adding glyph %d size=%d", glyph.index, glyph.data.size());
1456         glyphs.append(glyph);
1457         widths[i] = glyph.advanceWidth;
1458     }
1459
1460
1461     QList<QTtfTable> tables = generateGlyphTables(font, glyphs);
1462     tables.append(generateHead(font.head));
1463     tables.append(generateHhea(font.hhea));
1464     tables.append(generateMaxp(font.maxp));
1465     // name
1466     QTtfTable name_table;
1467     name_table.tag = MAKE_TAG('n', 'a', 'm', 'e');
1468     if (!noEmbed)
1469         name_table.data = fontEngine->getSfntTable(name_table.tag);
1470     if (name_table.data.isEmpty()) {
1471         qttf_name_table name;
1472         if (noEmbed)
1473             name.copyright = QLatin1String("Fake font");
1474         else
1475             name.copyright = QLatin1String(properties.copyright);
1476         name.family = fontEngine->fontDef.family;
1477         name.subfamily = QLatin1String("Regular"); // ######
1478         name.postscript_name = QLatin1String(properties.postscriptName);
1479         name_table = generateName(name);
1480     }
1481     tables.append(name_table);
1482
1483     if (!noEmbed) {
1484         QTtfTable os2;
1485         os2.tag = MAKE_TAG('O', 'S', '/', '2');
1486         os2.data = fontEngine->getSfntTable(os2.tag);
1487         if (!os2.data.isEmpty())
1488             tables.append(os2);
1489     }
1490
1491     return bindFont(tables);
1492 }
1493
1494 QT_END_NAMESPACE