source: trunk/src/gui/text/qfontsubset.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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