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

Last change on this file since 234 was 170, checked in by Dmitry A. Kuminov, 16 years ago

gui: Provided a temporary workaround for the mystic failure to build qfontsubset.cpp with QT_NO_FREETYPE removed.

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