2 |
- |
1 |
/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
|
|
2 |
|
|
|
3 |
This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
implied.
|
|
|
5 |
|
|
|
6 |
This software is distributed under license and may not be copied,
|
|
|
7 |
modified or distributed except as expressly authorized under the terms
|
|
|
8 |
of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
|
|
|
10 |
For more information about licensing, please refer to
|
|
|
11 |
http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
/* $Id: gdevpsft.c,v 1.35 2004/12/08 21:35:13 stefan Exp $ */
|
|
|
18 |
/* Write an embedded TrueType font */
|
|
|
19 |
#include "memory_.h"
|
|
|
20 |
#include <assert.h>
|
|
|
21 |
#include <stdlib.h> /* for qsort */
|
|
|
22 |
#include "gx.h"
|
|
|
23 |
#include "gscencs.h"
|
|
|
24 |
#include "gserrors.h"
|
|
|
25 |
#include "gsmatrix.h"
|
|
|
26 |
#include "gsutil.h"
|
|
|
27 |
#include "gxfcid.h"
|
|
|
28 |
#include "gxfont.h"
|
|
|
29 |
#include "gxfont42.h"
|
|
|
30 |
#include "gxttf.h"
|
|
|
31 |
#include "stream.h"
|
|
|
32 |
#include "spprint.h"
|
|
|
33 |
#include "gdevpsf.h"
|
|
|
34 |
|
|
|
35 |
/* Internally used options */
|
|
|
36 |
#define WRITE_TRUETYPE_STRIPPED 0x1000 /* internal */
|
|
|
37 |
#define WRITE_TRUETYPE_CID 0x2000 /* internal */
|
|
|
38 |
|
|
|
39 |
#define MAX_COMPOSITE_PIECES 3 /* adhoc */
|
|
|
40 |
|
|
|
41 |
/*
|
|
|
42 |
* The following are only for debugging. They force various format choices
|
|
|
43 |
* in the output. The normal (non-debugging) values for all of these are
|
|
|
44 |
* as indicated in the comments.
|
|
|
45 |
*
|
|
|
46 |
* Note that these options interact. Here is the complete list of settings
|
|
|
47 |
* that make sense.
|
|
|
48 |
|
|
|
49 |
0xf000 -1 N/A 1 0,1
|
|
|
50 |
0xf000 0,1 0,1 1 0,1
|
|
|
51 |
*/
|
|
|
52 |
/* Define whether to use the 0xf000 character bias for generated tables. */
|
|
|
53 |
#define TT_BIAS 0xf000 /* 0xf000 */
|
|
|
54 |
/* Define whether to use cmap format 6 never(-1), sometimes(0), always(1). */
|
|
|
55 |
#define TT_FORCE_CMAP_6 0 /* 0 */
|
|
|
56 |
/* Define whether to use the bias for the cmap format 6 "first code". */
|
|
|
57 |
#define TT_BIAS_CMAP_6 0 /* 0 */
|
|
|
58 |
/* Define whether to generate an OS/2 table if none is supplied. */
|
|
|
59 |
#define TT_GENERATE_OS_2 1 /* 1 */
|
|
|
60 |
/* Define whether to adjust the OS/2 range bits. */
|
|
|
61 |
#define TT_ADJUST_OS_2 1 /* 1 */
|
|
|
62 |
/*
|
|
|
63 |
* End of options.
|
|
|
64 |
*/
|
|
|
65 |
|
|
|
66 |
/* ---------------- Utilities ---------------- */
|
|
|
67 |
|
|
|
68 |
#define ACCESS(base, length, vptr)\
|
|
|
69 |
BEGIN\
|
|
|
70 |
code = string_proc(pfont, (ulong)(base), length, &vptr);\
|
|
|
71 |
if (code < 0) return code;\
|
|
|
72 |
END
|
|
|
73 |
|
|
|
74 |
/* Pad to a multiple of 4 bytes. */
|
|
|
75 |
private void
|
|
|
76 |
put_pad(stream *s, uint length)
|
|
|
77 |
{
|
|
|
78 |
static const byte pad_to_4[3] = {0, 0, 0};
|
|
|
79 |
|
|
|
80 |
stream_write(s, pad_to_4, (uint)(-(int)length & 3));
|
|
|
81 |
}
|
|
|
82 |
|
|
|
83 |
/* Put short and long values on a stream. */
|
|
|
84 |
private void
|
|
|
85 |
put_ushort(stream *s, uint v)
|
|
|
86 |
{
|
|
|
87 |
stream_putc(s, (byte)(v >> 8));
|
|
|
88 |
stream_putc(s, (byte)v);
|
|
|
89 |
}
|
|
|
90 |
private void
|
|
|
91 |
put_ulong(stream *s, ulong v)
|
|
|
92 |
{
|
|
|
93 |
put_ushort(s, (uint)(v >> 16));
|
|
|
94 |
put_ushort(s, (uint)v);
|
|
|
95 |
}
|
|
|
96 |
private void
|
|
|
97 |
put_loca(stream *s, ulong offset, int indexToLocFormat)
|
|
|
98 |
{
|
|
|
99 |
if (indexToLocFormat)
|
|
|
100 |
put_ulong(s, offset);
|
|
|
101 |
else
|
|
|
102 |
put_ushort(s, (uint)(offset >> 1));
|
|
|
103 |
}
|
|
|
104 |
|
|
|
105 |
/* Get or put 2- or 4-byte quantities from/into a table. */
|
|
|
106 |
#define U8(p) ((uint)((p)[0]))
|
|
|
107 |
#define S8(p) (int)((U8(p) ^ 0x80) - 0x80)
|
|
|
108 |
#define U16(p) (((uint)((p)[0]) << 8) + (p)[1])
|
|
|
109 |
#define S16(p) (int)((U16(p) ^ 0x8000) - 0x8000)
|
|
|
110 |
#define u32(p) get_u32_msb(p)
|
|
|
111 |
private void
|
|
|
112 |
put_u16(byte *p, uint v)
|
|
|
113 |
{
|
|
|
114 |
p[0] = (byte)(v >> 8);
|
|
|
115 |
p[1] = (byte)v;
|
|
|
116 |
}
|
|
|
117 |
private void
|
|
|
118 |
put_u32(byte *p, ulong v)
|
|
|
119 |
{
|
|
|
120 |
put_u16(p, (ushort)(v >> 16));
|
|
|
121 |
put_u16(p + 2, (ushort)v);
|
|
|
122 |
}
|
|
|
123 |
private ulong
|
|
|
124 |
put_table(byte tab[16], const char *tname, ulong checksum, ulong offset,
|
|
|
125 |
uint length)
|
|
|
126 |
{
|
|
|
127 |
memcpy(tab, (const byte *)tname, 4);
|
|
|
128 |
put_u32(tab + 4, checksum);
|
|
|
129 |
put_u32(tab + 8, offset + 0x40000000);
|
|
|
130 |
put_u32(tab + 12, (ulong)length);
|
|
|
131 |
return offset + round_up(length, 4);
|
|
|
132 |
}
|
|
|
133 |
|
|
|
134 |
/* Write one range of a TrueType font. */
|
|
|
135 |
private int
|
|
|
136 |
write_range(stream *s, gs_font_type42 *pfont, ulong start, uint length)
|
|
|
137 |
{
|
|
|
138 |
ulong base = start;
|
|
|
139 |
ulong limit = base + length;
|
|
|
140 |
|
|
|
141 |
if_debug3('l', "[l]write_range pos = %ld, start = %lu, length = %u\n",
|
|
|
142 |
stell(s), start, length);
|
|
|
143 |
while (base < limit) {
|
|
|
144 |
uint size = limit - base;
|
|
|
145 |
const byte *ptr;
|
|
|
146 |
int code;
|
|
|
147 |
|
|
|
148 |
/* Write the largest block we can access consecutively. */
|
|
|
149 |
while ((code = pfont->data.string_proc(pfont, base, size, &ptr)) < 0) {
|
|
|
150 |
if (size <= 1)
|
|
|
151 |
return code;
|
|
|
152 |
size >>= 1;
|
|
|
153 |
}
|
|
|
154 |
if (code > 0 && size > code)
|
|
|
155 |
size = code; /* Segmented data - see z42_string_proc. */
|
|
|
156 |
stream_write(s, ptr, size);
|
|
|
157 |
base += size;
|
|
|
158 |
}
|
|
|
159 |
return 0;
|
|
|
160 |
}
|
|
|
161 |
|
|
|
162 |
/*
|
|
|
163 |
* Determine the Macintosh glyph number for a given character, if any.
|
|
|
164 |
* If no glyph can be found, return -1 and store the name in *pstr.
|
|
|
165 |
*/
|
|
|
166 |
private int
|
|
|
167 |
mac_glyph_index(gs_font *font, int ch, gs_const_string *pstr)
|
|
|
168 |
{
|
|
|
169 |
gs_glyph glyph = font->procs.encode_char(font, (gs_char)ch,
|
|
|
170 |
GLYPH_SPACE_NAME);
|
|
|
171 |
int code;
|
|
|
172 |
|
|
|
173 |
if (glyph == gs_no_glyph)
|
|
|
174 |
return 0; /* .notdef */
|
|
|
175 |
code = font->procs.glyph_name(font, glyph, pstr);
|
|
|
176 |
assert(code >= 0);
|
|
|
177 |
if (glyph < gs_min_cid_glyph) {
|
|
|
178 |
gs_char mac_char;
|
|
|
179 |
gs_glyph mac_glyph;
|
|
|
180 |
gs_const_string mstr;
|
|
|
181 |
|
|
|
182 |
/* Look (not very hard) for a match in the Mac glyph space. */
|
|
|
183 |
if (ch >= 32 && ch <= 126)
|
|
|
184 |
mac_char = ch - 29;
|
|
|
185 |
else if (ch >= 128 && ch <= 255)
|
|
|
186 |
mac_char = ch - 30;
|
|
|
187 |
else
|
|
|
188 |
return -1;
|
|
|
189 |
mac_glyph = gs_c_known_encode(mac_char, ENCODING_INDEX_MACGLYPH);
|
|
|
190 |
if (mac_glyph == gs_no_glyph)
|
|
|
191 |
return -1;
|
|
|
192 |
code = gs_c_glyph_name(mac_glyph, &mstr);
|
|
|
193 |
assert(code >= 0);
|
|
|
194 |
if (!bytes_compare(pstr->data, pstr->size, mstr.data, mstr.size))
|
|
|
195 |
return (int)mac_char;
|
|
|
196 |
}
|
|
|
197 |
return -1;
|
|
|
198 |
}
|
|
|
199 |
|
|
|
200 |
/* ---------------- Individual tables ---------------- */
|
|
|
201 |
|
|
|
202 |
/* ------ cmap ------ */
|
|
|
203 |
|
|
|
204 |
/* Write a generated cmap table. */
|
|
|
205 |
static const byte cmap_initial_0[] = {
|
|
|
206 |
0, 0, /* table version # = 0 */
|
|
|
207 |
0, 2, /* # of encoding tables = 2 */
|
|
|
208 |
|
|
|
209 |
/* First table, Macintosh */
|
|
|
210 |
0, 1, /* platform ID = Macintosh */
|
|
|
211 |
0, 0, /* platform encoding ID = ??? */
|
|
|
212 |
0, 0, 0, 4+8+8, /* offset to table start */
|
|
|
213 |
/* Second table, Windows */
|
|
|
214 |
0, 3, /* platform ID = Microsoft */
|
|
|
215 |
0, 0, /* platform encoding ID = unknown */
|
|
|
216 |
0, 0, 1, 4+8+8+6, /* offset to table start */
|
|
|
217 |
|
|
|
218 |
/* Start of Macintosh format 0 table */
|
|
|
219 |
0, 0, /* format = 0, byte encoding table */
|
|
|
220 |
1, 6, /* length */
|
|
|
221 |
0, 0 /* version number */
|
|
|
222 |
};
|
|
|
223 |
static const byte cmap_initial_6[] = {
|
|
|
224 |
0, 0, /* table version # = 0 */
|
|
|
225 |
0, 2, /* # of encoding tables = 2 */
|
|
|
226 |
|
|
|
227 |
/* First table, Macintosh */
|
|
|
228 |
0, 1, /* platform ID = Macintosh */
|
|
|
229 |
0, 0, /* platform encoding ID = ??? */
|
|
|
230 |
0, 0, 0, 4+8+8, /* offset to table start */
|
|
|
231 |
/* Second table, Windows */
|
|
|
232 |
0, 3, /* platform ID = Microsoft */
|
|
|
233 |
0, 0, /* platform encoding ID = unknown */
|
|
|
234 |
0, 0, 0, 4+8+8+10, /* offset to table start */
|
|
|
235 |
/* *VARIABLE*, add 2 x # of entries */
|
|
|
236 |
|
|
|
237 |
/* Start of Macintosh format 6 table */
|
|
|
238 |
0, 6, /* format = 6, trimmed table mapping */
|
|
|
239 |
0, 10, /* length *VARIABLE*, add 2 x # of entries */
|
|
|
240 |
0, 0, /* version number */
|
|
|
241 |
0, 0, /* first character code */
|
|
|
242 |
0, 0 /* # of entries *VARIABLE* */
|
|
|
243 |
};
|
|
|
244 |
static const byte cmap_initial_4[] = {
|
|
|
245 |
0, 0, /* table version # = 0 */
|
|
|
246 |
0, 1, /* # of encoding tables = 2 */
|
|
|
247 |
|
|
|
248 |
/* Single table, Windows */
|
|
|
249 |
0, 3, /* platform ID = Microsoft */
|
|
|
250 |
0, 0, /* platform encoding ID = unknown */
|
|
|
251 |
0, 0, 0, 4+8 /* offset to table start */
|
|
|
252 |
};
|
|
|
253 |
static const byte cmap_sub_initial[] = {
|
|
|
254 |
0, 4, /* format = 4, segment mapping */
|
|
|
255 |
0, 32, /* length ** VARIABLE, add 2 x # of glyphs ** */
|
|
|
256 |
0, 0, /* version # */
|
|
|
257 |
0, 4, /* 2 x segCount */
|
|
|
258 |
0, 4, /* searchRange = 2 x 2 ^ floor(log2(segCount)) */
|
|
|
259 |
0, 1, /* floor(log2(segCount)) */
|
|
|
260 |
0, 0, /* 2 x segCount - searchRange */
|
|
|
261 |
|
|
|
262 |
0, 0, /* endCount[0] **VARIABLE** */
|
|
|
263 |
255, 255, /* endCount[1] */
|
|
|
264 |
0, 0, /* reservedPad */
|
|
|
265 |
0, 0, /* startCount[0] **VARIABLE** */
|
|
|
266 |
255, 255, /* startCount[1] */
|
|
|
267 |
0, 0, /* idDelta[0] */
|
|
|
268 |
0, 1, /* idDelta[1] */
|
|
|
269 |
0, 4, /* idRangeOffset[0] */
|
|
|
270 |
0, 0 /* idRangeOffset[1] */
|
|
|
271 |
};
|
|
|
272 |
/*
|
|
|
273 |
* The following nonsense is required because C defines sizeof()
|
|
|
274 |
* inconsistently.
|
|
|
275 |
*/
|
|
|
276 |
#define CMAP_ENTRIES_SIZE (256 * 2)
|
|
|
277 |
private void
|
|
|
278 |
write_cmap_0(stream *s, byte* entries /*[CMAP_ENTRIES_SIZE]*/, uint num_glyphs)
|
|
|
279 |
{
|
|
|
280 |
int i;
|
|
|
281 |
|
|
|
282 |
memset(entries + 2 * num_glyphs, 0, CMAP_ENTRIES_SIZE - 2 * num_glyphs);
|
|
|
283 |
stream_write(s, cmap_initial_0, sizeof(cmap_initial_0));
|
|
|
284 |
for (i = 0; i <= 0xff; ++i)
|
|
|
285 |
sputc(s, (byte)entries[2 * i + 1]);
|
|
|
286 |
}
|
|
|
287 |
private void
|
|
|
288 |
write_cmap_6(stream *s, byte *entries /*[CMAP_ENTRIES_SIZE]*/, uint first_code,
|
|
|
289 |
uint first_entry, uint num_entries)
|
|
|
290 |
{
|
|
|
291 |
byte cmap_data[sizeof(cmap_initial_6)];
|
|
|
292 |
|
|
|
293 |
memcpy(cmap_data, cmap_initial_6, sizeof(cmap_initial_6));
|
|
|
294 |
put_u16(cmap_data + 18,
|
|
|
295 |
U16(cmap_data + 18) + num_entries * 2); /* offset */
|
|
|
296 |
put_u16(cmap_data + 22,
|
|
|
297 |
U16(cmap_data + 22) + num_entries * 2); /* length */
|
|
|
298 |
put_u16(cmap_data + 26,
|
|
|
299 |
#if TT_BIAS_CMAP_6
|
|
|
300 |
first_code +
|
|
|
301 |
#endif
|
|
|
302 |
first_entry);
|
|
|
303 |
put_u16(cmap_data + 28, num_entries);
|
|
|
304 |
stream_write(s, cmap_data, sizeof(cmap_data));
|
|
|
305 |
stream_write(s, entries + first_entry * 2, num_entries * 2);
|
|
|
306 |
}
|
|
|
307 |
private void
|
|
|
308 |
write_cmap(stream *s, gs_font *font, uint first_code, int num_glyphs,
|
|
|
309 |
gs_glyph max_glyph, int options, uint cmap_length)
|
|
|
310 |
{
|
|
|
311 |
byte cmap_sub[sizeof(cmap_sub_initial)];
|
|
|
312 |
byte entries[CMAP_ENTRIES_SIZE];
|
|
|
313 |
int first_entry = 0, end_entry = num_glyphs;
|
|
|
314 |
bool can_use_trimmed = !(options & WRITE_TRUETYPE_NO_TRIMMED_TABLE);
|
|
|
315 |
uint merge = 0;
|
|
|
316 |
uint num_entries;
|
|
|
317 |
int i;
|
|
|
318 |
|
|
|
319 |
/* Collect the table entries. */
|
|
|
320 |
|
|
|
321 |
for (i = 0; i < num_glyphs; ++i) {
|
|
|
322 |
gs_glyph glyph =
|
|
|
323 |
font->procs.encode_char(font, (gs_char)i, GLYPH_SPACE_INDEX);
|
|
|
324 |
uint glyph_index;
|
|
|
325 |
|
|
|
326 |
if (glyph == gs_no_glyph || glyph < GS_MIN_GLYPH_INDEX ||
|
|
|
327 |
glyph > max_glyph
|
|
|
328 |
)
|
|
|
329 |
glyph = GS_MIN_GLYPH_INDEX;
|
|
|
330 |
glyph_index = (uint)(glyph - GS_MIN_GLYPH_INDEX);
|
|
|
331 |
merge |= glyph_index;
|
|
|
332 |
put_u16(entries + 2 * i, glyph_index);
|
|
|
333 |
}
|
|
|
334 |
while (end_entry > first_entry && !U16(entries + 2 * end_entry - 2))
|
|
|
335 |
--end_entry;
|
|
|
336 |
while (first_entry < end_entry && !U16(entries + 2 * first_entry))
|
|
|
337 |
++first_entry;
|
|
|
338 |
num_entries = end_entry - first_entry;
|
|
|
339 |
|
|
|
340 |
/* Write the table header and Macintosh sub-table (if any). */
|
|
|
341 |
|
|
|
342 |
#if TT_FORCE_CMAP_6 > 0
|
|
|
343 |
/* Always use format 6. */
|
|
|
344 |
write_cmap_6(s, entries, first_code, first_entry, num_entries);
|
|
|
345 |
#else
|
|
|
346 |
# if TT_FORCE_CMAP_6 < 0
|
|
|
347 |
/* Never use format 6. Use format 0 if possible. */
|
|
|
348 |
if (merge == (byte)merge)
|
|
|
349 |
write_cmap_0(s, entries, num_glyphs);
|
|
|
350 |
else
|
|
|
351 |
# else /* TT_FORCE_CMAP == 0 */
|
|
|
352 |
/*
|
|
|
353 |
* Use format 0 if possible and (economical or format 6 disallowed),
|
|
|
354 |
* otherwise format 6 if allowed.
|
|
|
355 |
*/
|
|
|
356 |
if (merge == (byte)merge && (num_entries <= 127 || !can_use_trimmed))
|
|
|
357 |
write_cmap_0(s, entries, num_glyphs);
|
|
|
358 |
else if (can_use_trimmed)
|
|
|
359 |
write_cmap_6(s, entries, first_code, first_entry, num_entries);
|
|
|
360 |
else
|
|
|
361 |
# endif
|
|
|
362 |
{
|
|
|
363 |
/*
|
|
|
364 |
* Punt. Acrobat Reader 3 can't handle any other Mac table format.
|
|
|
365 |
* (AR3 for Linux doesn't seem to be able to handle Windows format,
|
|
|
366 |
* either, but maybe AR3 for Windows can.)
|
|
|
367 |
*/
|
|
|
368 |
stream_write(s, cmap_initial_4, sizeof(cmap_initial_4));
|
|
|
369 |
}
|
|
|
370 |
#endif
|
|
|
371 |
|
|
|
372 |
/* Write the Windows sub-table. */
|
|
|
373 |
|
|
|
374 |
memcpy(cmap_sub, cmap_sub_initial, sizeof(cmap_sub_initial));
|
|
|
375 |
put_u16(cmap_sub + 2, U16(cmap_sub + 2) + num_entries * 2); /* length */
|
|
|
376 |
put_u16(cmap_sub + 14, first_code + end_entry - 1); /* endCount[0] */
|
|
|
377 |
put_u16(cmap_sub + 20, first_code + first_entry); /* startCount[0] */
|
|
|
378 |
stream_write(s, cmap_sub, sizeof(cmap_sub));
|
|
|
379 |
stream_write(s, entries + first_entry * 2, num_entries * 2);
|
|
|
380 |
put_pad(s, cmap_length);
|
|
|
381 |
}
|
|
|
382 |
private uint
|
|
|
383 |
size_cmap(gs_font *font, uint first_code, int num_glyphs, gs_glyph max_glyph,
|
|
|
384 |
int options)
|
|
|
385 |
{
|
|
|
386 |
stream poss;
|
|
|
387 |
|
|
|
388 |
s_init(&poss, NULL);
|
|
|
389 |
swrite_position_only(&poss);
|
|
|
390 |
write_cmap(&poss, font, first_code, num_glyphs, max_glyph, options, 0);
|
|
|
391 |
return stell(&poss);
|
|
|
392 |
}
|
|
|
393 |
|
|
|
394 |
/* ------ hmtx/vmtx ------ */
|
|
|
395 |
|
|
|
396 |
/*
|
|
|
397 |
* avoid fp exceptions storing large doubles into integers by limiting
|
|
|
398 |
* the range of the results. these are band-aids that don't fix the
|
|
|
399 |
* root cause of the out-of-range results, but they keep gs on the rails.
|
|
|
400 |
*/
|
|
|
401 |
|
|
|
402 |
ushort
|
|
|
403 |
limdbl2ushort(double d)
|
|
|
404 |
{
|
|
|
405 |
if (d < 0)
|
|
|
406 |
return 0;
|
|
|
407 |
else if (d > 64000)
|
|
|
408 |
return 64000;
|
|
|
409 |
else
|
|
|
410 |
return d;
|
|
|
411 |
}
|
|
|
412 |
|
|
|
413 |
long
|
|
|
414 |
limdbl2long(double d)
|
|
|
415 |
{
|
|
|
416 |
if (d > 2e9)
|
|
|
417 |
return 2e9;
|
|
|
418 |
else if (d < -2e9)
|
|
|
419 |
return -2e9;
|
|
|
420 |
else
|
|
|
421 |
return d;
|
|
|
422 |
}
|
|
|
423 |
|
|
|
424 |
private void
|
|
|
425 |
write_mtx(stream *s, gs_font_type42 *pfont, const gs_type42_mtx_t *pmtx,
|
|
|
426 |
int wmode)
|
|
|
427 |
{
|
|
|
428 |
uint num_metrics = pmtx->numMetrics;
|
|
|
429 |
uint len = num_metrics * 4;
|
|
|
430 |
double factor = pfont->data.unitsPerEm * (wmode ? -1 : 1);
|
|
|
431 |
float sbw[4];
|
|
|
432 |
uint i;
|
|
|
433 |
|
|
|
434 |
sbw[0] = sbw[1] = sbw[2] = sbw[3] = 0; /* in case of failures */
|
|
|
435 |
for (i = 0; i < pmtx->numMetrics; ++i) {
|
|
|
436 |
DISCARD(pfont->data.get_metrics(pfont, i, wmode, sbw));
|
|
|
437 |
put_ushort(s, limdbl2ushort(sbw[wmode + 2] * factor)); /* width */
|
|
|
438 |
put_ushort(s, limdbl2ushort(sbw[wmode] * factor)); /* lsb, may be <0 */
|
|
|
439 |
}
|
|
|
440 |
for (; len < pmtx->length; ++i, len += 2) {
|
|
|
441 |
DISCARD(pfont->data.get_metrics(pfont, i, wmode, sbw));
|
|
|
442 |
put_ushort(s, limdbl2ushort(sbw[wmode] * factor)); /* lsb, may be <0 */
|
|
|
443 |
}
|
|
|
444 |
}
|
|
|
445 |
|
|
|
446 |
/* Compute the metrics from the glyph_info. */
|
|
|
447 |
private uint
|
|
|
448 |
size_mtx(gs_font_type42 *pfont, gs_type42_mtx_t *pmtx, uint max_glyph,
|
|
|
449 |
int wmode)
|
|
|
450 |
{
|
|
|
451 |
int prev_width = min_int, wmode2;
|
|
|
452 |
uint last_width = 0; /* pacify compilers */
|
|
|
453 |
double factor = pfont->data.unitsPerEm * (wmode ? -1 : 1);
|
|
|
454 |
uint i, j;
|
|
|
455 |
|
|
|
456 |
for (i = 0; i <= max_glyph; ++i) {
|
|
|
457 |
float sbw[4];
|
|
|
458 |
int code, width;
|
|
|
459 |
|
|
|
460 |
for (j = 0; j < 4; j++)
|
|
|
461 |
sbw[j] = 0;
|
|
|
462 |
code = pfont->data.get_metrics(pfont, i, wmode, sbw);
|
|
|
463 |
if (code < 0)
|
|
|
464 |
continue;
|
|
|
465 |
wmode2 = wmode + 2;
|
|
|
466 |
if (wmode2 < 0 || wmode2 >= 4)
|
|
|
467 |
abort(); /* "wmode2 out of range" */
|
|
|
468 |
width = limdbl2long(sbw[wmode2] * factor + 0.5);
|
|
|
469 |
if (width != prev_width)
|
|
|
470 |
prev_width = width, last_width = i;
|
|
|
471 |
}
|
|
|
472 |
pmtx->numMetrics = last_width + 1;
|
|
|
473 |
pmtx->length = pmtx->numMetrics * 4 + (max_glyph - last_width) * 2;
|
|
|
474 |
return pmtx->length;
|
|
|
475 |
}
|
|
|
476 |
|
|
|
477 |
/* ------ name ------ */
|
|
|
478 |
|
|
|
479 |
/* Write a generated name table. */
|
|
|
480 |
static const byte name_initial[] = {
|
|
|
481 |
0, 0, /* format */
|
|
|
482 |
0, 1, /* # of records = 1 */
|
|
|
483 |
0, 18, /* start of string storage */
|
|
|
484 |
|
|
|
485 |
0, 2, /* platform ID = ISO */
|
|
|
486 |
0, 2, /* encoding ID = ISO 8859-1 */
|
|
|
487 |
0, 0, /* language ID (none) */
|
|
|
488 |
0, 6, /* name ID = PostScript name */
|
|
|
489 |
0, 0, /* length *VARIABLE* */
|
|
|
490 |
0, 0 /* start of string within string storage */
|
|
|
491 |
};
|
|
|
492 |
private uint
|
|
|
493 |
size_name(const gs_const_string *font_name)
|
|
|
494 |
{
|
|
|
495 |
return sizeof(name_initial) + font_name->size;
|
|
|
496 |
}
|
|
|
497 |
private void
|
|
|
498 |
write_name(stream *s, const gs_const_string *font_name)
|
|
|
499 |
{
|
|
|
500 |
byte name_bytes[sizeof(name_initial)];
|
|
|
501 |
|
|
|
502 |
memcpy(name_bytes, name_initial, sizeof(name_initial));
|
|
|
503 |
put_u16(name_bytes + 14, font_name->size);
|
|
|
504 |
stream_write(s, name_bytes, sizeof(name_bytes));
|
|
|
505 |
stream_write(s, font_name->data, font_name->size);
|
|
|
506 |
put_pad(s, size_name(font_name));
|
|
|
507 |
}
|
|
|
508 |
|
|
|
509 |
/* ------ OS/2 ------ */
|
|
|
510 |
|
|
|
511 |
/* Write a generated OS/2 table. */
|
|
|
512 |
#define OS_2_LENGTH sizeof(ttf_OS_2_t)
|
|
|
513 |
private void
|
|
|
514 |
update_OS_2(ttf_OS_2_t *pos2, uint first_glyph, int num_glyphs)
|
|
|
515 |
{
|
|
|
516 |
put_u16(pos2->usFirstCharIndex, first_glyph);
|
|
|
517 |
put_u16(pos2->usLastCharIndex, first_glyph + num_glyphs - 1);
|
|
|
518 |
#if TT_ADJUST_OS_2
|
|
|
519 |
if (first_glyph >= 0xf000) {
|
|
|
520 |
/* This font is being treated as a symbolic font. */
|
|
|
521 |
memset(pos2->ulUnicodeRanges, 0, sizeof(pos2->ulUnicodeRanges));
|
|
|
522 |
pos2->ulUnicodeRanges[7] = 8; /* bit 60, private use range */
|
|
|
523 |
memset(pos2->ulCodePageRanges, 0, sizeof(pos2->ulCodePageRanges));
|
|
|
524 |
pos2->ulCodePageRanges[3] = 1; /* bit 31, symbolic */
|
|
|
525 |
}
|
|
|
526 |
#endif
|
|
|
527 |
}
|
|
|
528 |
private void
|
|
|
529 |
write_OS_2(stream *s, gs_font *font, uint first_glyph, int num_glyphs)
|
|
|
530 |
{
|
|
|
531 |
ttf_OS_2_t os2;
|
|
|
532 |
|
|
|
533 |
/*
|
|
|
534 |
* We don't bother to set most of the fields. The really important
|
|
|
535 |
* ones, which affect character mapping, are usFirst/LastCharIndex.
|
|
|
536 |
* We also need to set usWeightClass and usWidthClass to avoid
|
|
|
537 |
* crashing ttfdump.
|
|
|
538 |
*/
|
|
|
539 |
memset(&os2, 0, sizeof(os2));
|
|
|
540 |
put_u16(os2.version, 1);
|
|
|
541 |
put_u16(os2.usWeightClass, 400); /* Normal */
|
|
|
542 |
put_u16(os2.usWidthClass, 5); /* Normal */
|
|
|
543 |
update_OS_2(&os2, first_glyph, num_glyphs);
|
|
|
544 |
stream_write(s, &os2, sizeof(os2));
|
|
|
545 |
put_pad(s, sizeof(os2));
|
|
|
546 |
}
|
|
|
547 |
|
|
|
548 |
/* ------ post ------ */
|
|
|
549 |
|
|
|
550 |
/* Construct and then write the post table. */
|
|
|
551 |
typedef struct post_glyph_s {
|
|
|
552 |
byte char_index;
|
|
|
553 |
byte size;
|
|
|
554 |
ushort glyph_index;
|
|
|
555 |
} post_glyph_t;
|
|
|
556 |
private int
|
|
|
557 |
compare_post_glyphs(const void *pg1, const void *pg2)
|
|
|
558 |
{
|
|
|
559 |
gs_glyph g1 = ((const post_glyph_t *)pg1)->glyph_index,
|
|
|
560 |
g2 = ((const post_glyph_t *)pg2)->glyph_index;
|
|
|
561 |
|
|
|
562 |
return (g1 < g2 ? -1 : g1 > g2 ? 1 : 0);
|
|
|
563 |
}
|
|
|
564 |
typedef struct post_s {
|
|
|
565 |
post_glyph_t glyphs[256 + 1];
|
|
|
566 |
int count, glyph_count;
|
|
|
567 |
uint length;
|
|
|
568 |
} post_t;
|
|
|
569 |
|
|
|
570 |
/*
|
|
|
571 |
* If necessary, compute the length of the post table. Note that we
|
|
|
572 |
* only generate post entries for characters in the Encoding.
|
|
|
573 |
*/
|
|
|
574 |
private void
|
|
|
575 |
compute_post(gs_font *font, post_t *post)
|
|
|
576 |
{
|
|
|
577 |
int i;
|
|
|
578 |
|
|
|
579 |
for (i = 0, post->length = 32 + 2; i <= 255; ++i) {
|
|
|
580 |
gs_const_string str;
|
|
|
581 |
gs_glyph glyph = font->procs.encode_char(font, (gs_char)i,
|
|
|
582 |
GLYPH_SPACE_INDEX);
|
|
|
583 |
int mac_index = mac_glyph_index(font, i, &str);
|
|
|
584 |
|
|
|
585 |
if (mac_index != 0) {
|
|
|
586 |
post->glyphs[post->count].char_index = i;
|
|
|
587 |
post->glyphs[post->count].size =
|
|
|
588 |
(mac_index < 0 ? str.size + 1 : 0);
|
|
|
589 |
post->glyphs[post->count].glyph_index = glyph - GS_MIN_GLYPH_INDEX;
|
|
|
590 |
post->count++;
|
|
|
591 |
}
|
|
|
592 |
}
|
|
|
593 |
if (post->count) {
|
|
|
594 |
int j;
|
|
|
595 |
|
|
|
596 |
qsort(post->glyphs, post->count, sizeof(post->glyphs[0]),
|
|
|
597 |
compare_post_glyphs);
|
|
|
598 |
/* Eliminate duplicate references to the same glyph. */
|
|
|
599 |
for (i = j = 0; i < post->count; ++i) {
|
|
|
600 |
if (i == 0 ||
|
|
|
601 |
post->glyphs[i].glyph_index !=
|
|
|
602 |
post->glyphs[i - 1].glyph_index
|
|
|
603 |
) {
|
|
|
604 |
post->length += post->glyphs[i].size;
|
|
|
605 |
post->glyphs[j++] = post->glyphs[i];
|
|
|
606 |
}
|
|
|
607 |
}
|
|
|
608 |
post->count = j;
|
|
|
609 |
post->glyph_count = post->glyphs[post->count - 1].glyph_index + 1;
|
|
|
610 |
}
|
|
|
611 |
post->length += post->glyph_count * 2;
|
|
|
612 |
}
|
|
|
613 |
|
|
|
614 |
/* Write the post table */
|
|
|
615 |
private void
|
|
|
616 |
write_post(stream *s, gs_font *font, post_t *post)
|
|
|
617 |
{
|
|
|
618 |
byte post_initial[32 + 2];
|
|
|
619 |
uint name_index;
|
|
|
620 |
uint glyph_index;
|
|
|
621 |
int i;
|
|
|
622 |
|
|
|
623 |
memset(post_initial, 0, 32);
|
|
|
624 |
put_u32(post_initial, 0x00020000);
|
|
|
625 |
put_u16(post_initial + 32, post->glyph_count);
|
|
|
626 |
stream_write(s, post_initial, sizeof(post_initial));
|
|
|
627 |
|
|
|
628 |
/* Write the name index table. */
|
|
|
629 |
|
|
|
630 |
for (i = 0, name_index = 258, glyph_index = 0; i < post->count; ++i) {
|
|
|
631 |
gs_const_string str;
|
|
|
632 |
int ch = post->glyphs[i].char_index;
|
|
|
633 |
int mac_index = mac_glyph_index(font, ch, &str);
|
|
|
634 |
|
|
|
635 |
for (; glyph_index < post->glyphs[i].glyph_index; ++glyph_index)
|
|
|
636 |
put_ushort(s, 0);
|
|
|
637 |
glyph_index++;
|
|
|
638 |
if (mac_index >= 0)
|
|
|
639 |
put_ushort(s, mac_index);
|
|
|
640 |
else {
|
|
|
641 |
put_ushort(s, name_index);
|
|
|
642 |
name_index++;
|
|
|
643 |
}
|
|
|
644 |
}
|
|
|
645 |
|
|
|
646 |
/* Write the string names of the glyphs. */
|
|
|
647 |
|
|
|
648 |
for (i = 0; i < post->count; ++i) {
|
|
|
649 |
gs_const_string str;
|
|
|
650 |
int ch = post->glyphs[i].char_index;
|
|
|
651 |
int mac_index = mac_glyph_index(font, ch, &str);
|
|
|
652 |
|
|
|
653 |
if (mac_index < 0) {
|
|
|
654 |
spputc(s, (byte)str.size);
|
|
|
655 |
stream_write(s, str.data, str.size);
|
|
|
656 |
}
|
|
|
657 |
}
|
|
|
658 |
put_pad(s, post->length);
|
|
|
659 |
}
|
|
|
660 |
|
|
|
661 |
/* ---------------- Main program ---------------- */
|
|
|
662 |
|
|
|
663 |
/* Write the definition of a TrueType font. */
|
|
|
664 |
private int
|
|
|
665 |
compare_table_tags(const void *pt1, const void *pt2)
|
|
|
666 |
{
|
|
|
667 |
ulong t1 = u32(pt1), t2 = u32(pt2);
|
|
|
668 |
|
|
|
669 |
return (t1 < t2 ? -1 : t1 > t2 ? 1 : 0);
|
|
|
670 |
}
|
|
|
671 |
private int
|
|
|
672 |
psf_write_truetype_data(stream *s, gs_font_type42 *pfont, int options,
|
|
|
673 |
psf_glyph_enum_t *penum, bool is_subset,
|
|
|
674 |
const gs_const_string *alt_font_name)
|
|
|
675 |
{
|
|
|
676 |
gs_font *const font = (gs_font *)pfont;
|
|
|
677 |
gs_const_string font_name;
|
|
|
678 |
int (*string_proc)(gs_font_type42 *, ulong, uint, const byte **) =
|
|
|
679 |
pfont->data.string_proc;
|
|
|
680 |
const byte *OffsetTable;
|
|
|
681 |
uint numTables_stored, numTables, numTables_out;
|
|
|
682 |
#define MAX_NUM_TABLES 40
|
|
|
683 |
byte tables[MAX_NUM_TABLES * 16];
|
|
|
684 |
uint i;
|
|
|
685 |
ulong offset;
|
|
|
686 |
gs_glyph glyph, glyph_prev;
|
|
|
687 |
ulong max_glyph;
|
|
|
688 |
uint glyf_length, loca_length;
|
|
|
689 |
ulong glyf_checksum = 0L; /****** NO CHECKSUM ******/
|
|
|
690 |
ulong loca_checksum[2] = {0L,0L};
|
|
|
691 |
ulong glyf_alignment = 0;
|
|
|
692 |
uint numGlyphs = 0; /* original value from maxp */
|
|
|
693 |
byte head[56]; /* 0 mod 4 */
|
|
|
694 |
gs_type42_mtx_t mtx[2];
|
|
|
695 |
post_t post;
|
|
|
696 |
ulong head_checksum, file_checksum = 0;
|
|
|
697 |
int indexToLocFormat = 0;
|
|
|
698 |
bool
|
|
|
699 |
writing_cid = (options & WRITE_TRUETYPE_CID) != 0,
|
|
|
700 |
writing_stripped = (options & WRITE_TRUETYPE_STRIPPED) != 0,
|
|
|
701 |
generate_mtx = (options & WRITE_TRUETYPE_HVMTX) != 0,
|
|
|
702 |
no_generate = writing_cid | writing_stripped,
|
|
|
703 |
have_cmap = no_generate,
|
|
|
704 |
have_name = !(options & WRITE_TRUETYPE_NAME),
|
|
|
705 |
have_OS_2 = no_generate,
|
|
|
706 |
have_post = no_generate;
|
|
|
707 |
int have_hvhea[2];
|
|
|
708 |
uint cmap_length = 0;
|
|
|
709 |
ulong OS_2_start = 0;
|
|
|
710 |
uint OS_2_length = OS_2_LENGTH;
|
|
|
711 |
int code;
|
|
|
712 |
|
|
|
713 |
have_hvhea[0] = have_hvhea[1] = 0;
|
|
|
714 |
if (alt_font_name)
|
|
|
715 |
font_name = *alt_font_name;
|
|
|
716 |
else
|
|
|
717 |
font_name.data = font->font_name.chars,
|
|
|
718 |
font_name.size = font->font_name.size;
|
|
|
719 |
|
|
|
720 |
/*
|
|
|
721 |
* Count the number of tables, including the eventual glyf and loca
|
|
|
722 |
* (which may not actually be present in the font), and copy the
|
|
|
723 |
* table directory.
|
|
|
724 |
*/
|
|
|
725 |
|
|
|
726 |
ACCESS(0, 12, OffsetTable);
|
|
|
727 |
numTables_stored = U16(OffsetTable + 4);
|
|
|
728 |
for (i = numTables = 0; i < numTables_stored; ++i) {
|
|
|
729 |
const byte *tab;
|
|
|
730 |
const byte *data;
|
|
|
731 |
ulong start;
|
|
|
732 |
uint length;
|
|
|
733 |
|
|
|
734 |
if (numTables == MAX_NUM_TABLES)
|
|
|
735 |
return_error(gs_error_limitcheck);
|
|
|
736 |
ACCESS(12 + i * 16, 16, tab);
|
|
|
737 |
start = u32(tab + 8);
|
|
|
738 |
length = u32(tab + 12);
|
|
|
739 |
/* Copy the table data now, since another ACCESS may invalidate it. */
|
|
|
740 |
memcpy(&tables[numTables * 16], tab, 16);
|
|
|
741 |
|
|
|
742 |
#define W(a,b,c,d)\
|
|
|
743 |
( ((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
|
|
|
744 |
|
|
|
745 |
switch (u32(tab)) {
|
|
|
746 |
case W('h','e','a','d'):
|
|
|
747 |
if (length != 54)
|
|
|
748 |
return_error(gs_error_invalidfont);
|
|
|
749 |
ACCESS(start, length, data);
|
|
|
750 |
memcpy(head, data, length);
|
|
|
751 |
continue;
|
|
|
752 |
case W('g','l','y','f'): /* synthesized */
|
|
|
753 |
case W('g','l','y','x'): /* Adobe bogus */
|
|
|
754 |
case W('l','o','c','a'): /* synthesized */
|
|
|
755 |
case W('l','o','c','x'): /* Adobe bogus */
|
|
|
756 |
case W('g','d','i','r'): /* Adobe marker */
|
|
|
757 |
continue;
|
|
|
758 |
case W('c','m','a','p'):
|
|
|
759 |
if (options & (WRITE_TRUETYPE_CMAP | WRITE_TRUETYPE_CID))
|
|
|
760 |
continue;
|
|
|
761 |
have_cmap = true;
|
|
|
762 |
break;
|
|
|
763 |
case W('m','a','x','p'):
|
|
|
764 |
ACCESS(start, length, data);
|
|
|
765 |
numGlyphs = U16(data + 4);
|
|
|
766 |
break;
|
|
|
767 |
case W('n','a','m','e'):
|
|
|
768 |
if (writing_cid)
|
|
|
769 |
continue;
|
|
|
770 |
have_name = true;
|
|
|
771 |
break;
|
|
|
772 |
case W('O','S','/','2'):
|
|
|
773 |
if (writing_cid)
|
|
|
774 |
continue;
|
|
|
775 |
have_OS_2 = true;
|
|
|
776 |
if (length > OS_2_LENGTH)
|
|
|
777 |
return_error(gs_error_invalidfont);
|
|
|
778 |
OS_2_start = start;
|
|
|
779 |
OS_2_length = length;
|
|
|
780 |
continue;
|
|
|
781 |
case W('p','o','s','t'):
|
|
|
782 |
have_post = true;
|
|
|
783 |
break;
|
|
|
784 |
case W('h','h','e','a'):
|
|
|
785 |
have_hvhea[0] = 1;
|
|
|
786 |
break;
|
|
|
787 |
case W('v','h','e','a'):
|
|
|
788 |
have_hvhea[1] = 1;
|
|
|
789 |
break;
|
|
|
790 |
case W('h','m','t','x'):
|
|
|
791 |
case W('v','m','t','x'):
|
|
|
792 |
if (generate_mtx)
|
|
|
793 |
continue;
|
|
|
794 |
/* falls through */
|
|
|
795 |
case W('c','v','t',' '):
|
|
|
796 |
case W('f','p','g','m'):
|
|
|
797 |
case W('g','a','s','p'):
|
|
|
798 |
case W('k','e','r','n'):
|
|
|
799 |
case W('p','r','e','p'):
|
|
|
800 |
break; /* always copy these if present */
|
|
|
801 |
default:
|
|
|
802 |
if (writing_cid)
|
|
|
803 |
continue;
|
|
|
804 |
break;
|
|
|
805 |
}
|
|
|
806 |
numTables++;
|
|
|
807 |
}
|
|
|
808 |
|
|
|
809 |
/*
|
|
|
810 |
* Enumerate the glyphs to get the size of glyf and loca,
|
|
|
811 |
* and to compute the checksums for these tables.
|
|
|
812 |
*/
|
|
|
813 |
|
|
|
814 |
/****** NO CHECKSUMS YET ******/
|
|
|
815 |
for (max_glyph = 0, glyf_length = 0;
|
|
|
816 |
(code = psf_enumerate_glyphs_next(penum, &glyph)) != 1;
|
|
|
817 |
) {
|
|
|
818 |
uint glyph_index;
|
|
|
819 |
gs_glyph_data_t glyph_data;
|
|
|
820 |
|
|
|
821 |
if (glyph < gs_min_cid_glyph)
|
|
|
822 |
return_error(gs_error_invalidfont);
|
|
|
823 |
glyph_index = glyph & ~GS_GLYPH_TAG;
|
|
|
824 |
if_debug1('L', "[L]glyph_index %u\n", glyph_index);
|
|
|
825 |
glyph_data.memory = pfont->memory;
|
|
|
826 |
if ((code = pfont->data.get_outline(pfont, glyph_index, &glyph_data)) >= 0) {
|
|
|
827 |
/* Since indexToLocFormat==0 assumes even glyph lengths,
|
|
|
828 |
round it up here. If later we choose indexToLocFormat==1,
|
|
|
829 |
subtract the glyf_alignment to compensate it. */
|
|
|
830 |
uint l = (glyph_data.bits.size + 1) & ~1;
|
|
|
831 |
|
|
|
832 |
max_glyph = max(max_glyph, glyph_index);
|
|
|
833 |
glyf_length += l;
|
|
|
834 |
if (l != glyph_data.bits.size)
|
|
|
835 |
glyf_alignment++;
|
|
|
836 |
if_debug1('L', "[L] size %u\n", glyph_data.bits.size);
|
|
|
837 |
gs_glyph_data_free(&glyph_data, "psf_write_truetype_data");
|
|
|
838 |
}
|
|
|
839 |
}
|
|
|
840 |
/*
|
|
|
841 |
* For subset fonts, we should trim the loca table so that it only
|
|
|
842 |
* contains entries through max_glyph. Unfortunately, this would
|
|
|
843 |
* require changing numGlyphs in maxp, which in turn would affect hdmx,
|
|
|
844 |
* hhea, hmtx, vdmx, vhea, vmtx, and possibly other tables. This is way
|
|
|
845 |
* more work than we want to do right now.
|
|
|
846 |
*/
|
|
|
847 |
if (writing_stripped) {
|
|
|
848 |
glyf_length = 0;
|
|
|
849 |
loca_length = 0;
|
|
|
850 |
} else {
|
|
|
851 |
/*loca_length = (max_glyph + 2) << 2;*/
|
|
|
852 |
loca_length = (numGlyphs + 1) << 2;
|
|
|
853 |
indexToLocFormat = (glyf_length > 0x1fffc);
|
|
|
854 |
if (!indexToLocFormat)
|
|
|
855 |
loca_length >>= 1;
|
|
|
856 |
else
|
|
|
857 |
glyf_length -= glyf_alignment;
|
|
|
858 |
/* Acrobat Reader won't accept fonts with empty glyfs. */
|
|
|
859 |
if (glyf_length == 0)
|
|
|
860 |
glyf_length = 1;
|
|
|
861 |
}
|
|
|
862 |
if_debug2('l', "[l]max_glyph = %lu, glyf_length = %lu\n",
|
|
|
863 |
(ulong)max_glyph, (ulong)glyf_length);
|
|
|
864 |
|
|
|
865 |
/*
|
|
|
866 |
* If necessary, compute the length of the post table. Note that we
|
|
|
867 |
* only generate post entries for characters in the Encoding. */
|
|
|
868 |
|
|
|
869 |
if (!have_post) {
|
|
|
870 |
memset(&post, 0, sizeof(post));
|
|
|
871 |
if (options & WRITE_TRUETYPE_POST)
|
|
|
872 |
compute_post(font, &post);
|
|
|
873 |
else
|
|
|
874 |
post.length = 32; /* dummy table */
|
|
|
875 |
}
|
|
|
876 |
|
|
|
877 |
/* Fix up the head table. */
|
|
|
878 |
|
|
|
879 |
memset(head + 8, 0, 4);
|
|
|
880 |
head[51] = (byte)indexToLocFormat;
|
|
|
881 |
memset(head + 54, 0, 2);
|
|
|
882 |
for (head_checksum = 0, i = 0; i < 56; i += 4)
|
|
|
883 |
head_checksum += u32(&head[i]);
|
|
|
884 |
|
|
|
885 |
/*
|
|
|
886 |
* Construct the table directory, except for glyf, loca, head, OS/2,
|
|
|
887 |
* and, if necessary, generated cmap, name, and post tables.
|
|
|
888 |
* Note that the existing directory is already sorted by tag.
|
|
|
889 |
*/
|
|
|
890 |
|
|
|
891 |
numTables_out = numTables + 1 /* head */
|
|
|
892 |
+ !writing_stripped * 2 /* glyf, loca */
|
|
|
893 |
+ generate_mtx * (have_hvhea[0] + have_hvhea[1]) /* hmtx, vmtx */
|
|
|
894 |
+ !have_OS_2 /* OS/2 */
|
|
|
895 |
+ !have_cmap + !have_name + !have_post;
|
|
|
896 |
if (numTables_out >= MAX_NUM_TABLES)
|
|
|
897 |
return_error(gs_error_limitcheck);
|
|
|
898 |
offset = 12 + numTables_out * 16;
|
|
|
899 |
for (i = 0; i < numTables; ++i) {
|
|
|
900 |
byte *tab = &tables[i * 16];
|
|
|
901 |
ulong length = u32(tab + 12);
|
|
|
902 |
|
|
|
903 |
offset += round_up(length, 4);
|
|
|
904 |
}
|
|
|
905 |
|
|
|
906 |
/* Make the table directory entries for generated tables. */
|
|
|
907 |
|
|
|
908 |
{
|
|
|
909 |
byte *tab = &tables[numTables * 16];
|
|
|
910 |
|
|
|
911 |
if (!writing_stripped) {
|
|
|
912 |
offset = put_table(tab, "glyf", glyf_checksum,
|
|
|
913 |
offset, glyf_length);
|
|
|
914 |
tab += 16;
|
|
|
915 |
|
|
|
916 |
offset = put_table(tab, "loca", loca_checksum[indexToLocFormat],
|
|
|
917 |
offset, loca_length);
|
|
|
918 |
tab += 16;
|
|
|
919 |
}
|
|
|
920 |
|
|
|
921 |
if (!have_cmap) {
|
|
|
922 |
cmap_length = size_cmap(font, TT_BIAS, 256,
|
|
|
923 |
GS_MIN_GLYPH_INDEX + max_glyph, options);
|
|
|
924 |
offset = put_table(tab, "cmap", 0L /****** NO CHECKSUM ******/,
|
|
|
925 |
offset, cmap_length);
|
|
|
926 |
tab += 16;
|
|
|
927 |
}
|
|
|
928 |
|
|
|
929 |
if (!have_name) {
|
|
|
930 |
offset = put_table(tab, "name", 0L /****** NO CHECKSUM ******/,
|
|
|
931 |
offset, size_name(&font_name));
|
|
|
932 |
tab += 16;
|
|
|
933 |
}
|
|
|
934 |
|
|
|
935 |
if (!no_generate) {
|
|
|
936 |
offset = put_table(tab, "OS/2", 0L /****** NO CHECKSUM ******/,
|
|
|
937 |
offset, OS_2_length);
|
|
|
938 |
tab += 16;
|
|
|
939 |
}
|
|
|
940 |
|
|
|
941 |
if (generate_mtx)
|
|
|
942 |
for (i = 0; i < 2; ++i)
|
|
|
943 |
if (have_hvhea[i]) {
|
|
|
944 |
offset = put_table(tab, (i ? "vmtx" : "hmtx"),
|
|
|
945 |
0L /****** NO CHECKSUM ******/,
|
|
|
946 |
offset,
|
|
|
947 |
size_mtx(pfont, &mtx[i], max_glyph, i));
|
|
|
948 |
tab += 16;
|
|
|
949 |
}
|
|
|
950 |
|
|
|
951 |
if (!have_post) {
|
|
|
952 |
offset = put_table(tab, "post", 0L /****** NO CHECKSUM ******/,
|
|
|
953 |
offset, post.length);
|
|
|
954 |
tab += 16;
|
|
|
955 |
}
|
|
|
956 |
|
|
|
957 |
/*
|
|
|
958 |
* Note that the 'head' table must have length 54, even though
|
|
|
959 |
* it occupies 56 bytes on the file.
|
|
|
960 |
*/
|
|
|
961 |
offset = put_table(tab, "head", head_checksum, offset, 54);
|
|
|
962 |
tab += 16;
|
|
|
963 |
}
|
|
|
964 |
numTables = numTables_out;
|
|
|
965 |
|
|
|
966 |
/* Write the font header. */
|
|
|
967 |
|
|
|
968 |
{
|
|
|
969 |
static const byte version[4] = {0, 1, 0, 0};
|
|
|
970 |
|
|
|
971 |
stream_write(s, version, 4);
|
|
|
972 |
}
|
|
|
973 |
put_ushort(s, numTables);
|
|
|
974 |
for (i = 0; 1 << i <= numTables; ++i)
|
|
|
975 |
DO_NOTHING;
|
|
|
976 |
--i;
|
|
|
977 |
put_ushort(s, 16 << i); /* searchRange */
|
|
|
978 |
put_ushort(s, i); /* entrySelectors */
|
|
|
979 |
put_ushort(s, numTables * 16 - (16 << i)); /* rangeShift */
|
|
|
980 |
|
|
|
981 |
/* Write the table directory. */
|
|
|
982 |
|
|
|
983 |
qsort(tables, numTables, 16, compare_table_tags);
|
|
|
984 |
offset = 12 + numTables * 16;
|
|
|
985 |
for (i = 0; i < numTables; ++i) {
|
|
|
986 |
const byte *tab = &tables[i * 16];
|
|
|
987 |
byte entry[16];
|
|
|
988 |
|
|
|
989 |
memcpy(entry, tab, 16);
|
|
|
990 |
if (entry[8] < 0x40) {
|
|
|
991 |
/* Not a generated table. */
|
|
|
992 |
uint length = u32(tab + 12);
|
|
|
993 |
|
|
|
994 |
put_u32(entry + 8, offset);
|
|
|
995 |
offset += round_up(length, 4);
|
|
|
996 |
} else {
|
|
|
997 |
entry[8] -= 0x40;
|
|
|
998 |
}
|
|
|
999 |
stream_write(s, entry, 16);
|
|
|
1000 |
}
|
|
|
1001 |
|
|
|
1002 |
/* Write tables other than the ones we generate here. */
|
|
|
1003 |
|
|
|
1004 |
for (i = 0; i < numTables; ++i) {
|
|
|
1005 |
const byte *tab = &tables[i * 16];
|
|
|
1006 |
|
|
|
1007 |
if (tab[8] < 0x40) {
|
|
|
1008 |
ulong start = u32(tab + 8);
|
|
|
1009 |
uint length = u32(tab + 12);
|
|
|
1010 |
|
|
|
1011 |
switch (u32(tab)) {
|
|
|
1012 |
case W('O','S','/','2'):
|
|
|
1013 |
if (!have_cmap) {
|
|
|
1014 |
/*
|
|
|
1015 |
* Adjust the first and last character indices in the OS/2
|
|
|
1016 |
* table to reflect the values in the generated cmap.
|
|
|
1017 |
*/
|
|
|
1018 |
const byte *pos2;
|
|
|
1019 |
ttf_OS_2_t os2;
|
|
|
1020 |
|
|
|
1021 |
ACCESS(OS_2_start, OS_2_length, pos2);
|
|
|
1022 |
memcpy(&os2, pos2, min(OS_2_length, sizeof(os2)));
|
|
|
1023 |
update_OS_2(&os2, TT_BIAS, 256);
|
|
|
1024 |
stream_write(s, &os2, OS_2_length);
|
|
|
1025 |
put_pad(s, OS_2_length);
|
|
|
1026 |
} else {
|
|
|
1027 |
/* Just copy the existing OS/2 table. */
|
|
|
1028 |
write_range(s, pfont, OS_2_start, OS_2_length);
|
|
|
1029 |
put_pad(s, OS_2_length);
|
|
|
1030 |
}
|
|
|
1031 |
break;
|
|
|
1032 |
case W('h','h','e','a'):
|
|
|
1033 |
case W('v','h','e','a'):
|
|
|
1034 |
if (generate_mtx) {
|
|
|
1035 |
write_range(s, pfont, start, length - 2); /* 34 */
|
|
|
1036 |
put_ushort(s, mtx[tab[0] == 'v'].numMetrics);
|
|
|
1037 |
break;
|
|
|
1038 |
}
|
|
|
1039 |
/* falls through */
|
|
|
1040 |
default:
|
|
|
1041 |
write_range(s, pfont, start, length);
|
|
|
1042 |
}
|
|
|
1043 |
put_pad(s, length);
|
|
|
1044 |
}
|
|
|
1045 |
}
|
|
|
1046 |
|
|
|
1047 |
if (!writing_stripped) {
|
|
|
1048 |
|
|
|
1049 |
/* Write glyf. */
|
|
|
1050 |
|
|
|
1051 |
psf_enumerate_glyphs_reset(penum);
|
|
|
1052 |
for (offset = 0; psf_enumerate_glyphs_next(penum, &glyph) != 1; ) {
|
|
|
1053 |
gs_glyph_data_t glyph_data;
|
|
|
1054 |
|
|
|
1055 |
glyph_data.memory = pfont->memory;
|
|
|
1056 |
if ((code = pfont->data.get_outline(pfont,
|
|
|
1057 |
glyph & ~GS_GLYPH_TAG,
|
|
|
1058 |
&glyph_data)) >= 0
|
|
|
1059 |
) {
|
|
|
1060 |
uint l = glyph_data.bits.size, zero = 0;
|
|
|
1061 |
|
|
|
1062 |
if (!indexToLocFormat)
|
|
|
1063 |
l = (l + 1) & ~1;
|
|
|
1064 |
stream_write(s, glyph_data.bits.data, glyph_data.bits.size);
|
|
|
1065 |
if (glyph_data.bits.size < l)
|
|
|
1066 |
stream_write(s, &zero, 1);
|
|
|
1067 |
offset += l;
|
|
|
1068 |
if_debug2('L', "[L]glyf index = %u, size = %u\n",
|
|
|
1069 |
i, glyph_data.bits.size);
|
|
|
1070 |
gs_glyph_data_free(&glyph_data, "psf_write_truetype_data");
|
|
|
1071 |
}
|
|
|
1072 |
}
|
|
|
1073 |
if_debug1('l', "[l]glyf final offset = %lu\n", offset);
|
|
|
1074 |
/* Add a dummy byte if necessary to make glyf non-empty. */
|
|
|
1075 |
while (offset < glyf_length)
|
|
|
1076 |
stream_putc(s, 0), ++offset;
|
|
|
1077 |
put_pad(s, (uint)offset);
|
|
|
1078 |
|
|
|
1079 |
/* Write loca. */
|
|
|
1080 |
|
|
|
1081 |
psf_enumerate_glyphs_reset(penum);
|
|
|
1082 |
glyph_prev = 0;
|
|
|
1083 |
for (offset = 0; psf_enumerate_glyphs_next(penum, &glyph) != 1; ) {
|
|
|
1084 |
gs_glyph_data_t glyph_data;
|
|
|
1085 |
uint glyph_index = glyph & ~GS_GLYPH_TAG;
|
|
|
1086 |
|
|
|
1087 |
for (; glyph_prev <= glyph_index; ++glyph_prev)
|
|
|
1088 |
put_loca(s, offset, indexToLocFormat);
|
|
|
1089 |
glyph_data.memory = pfont->memory;
|
|
|
1090 |
if ((code = pfont->data.get_outline(pfont, glyph_index,
|
|
|
1091 |
&glyph_data)) >= 0
|
|
|
1092 |
) {
|
|
|
1093 |
uint l = glyph_data.bits.size;
|
|
|
1094 |
|
|
|
1095 |
if (!indexToLocFormat)
|
|
|
1096 |
l = (l + 1) & ~1;
|
|
|
1097 |
offset += l;
|
|
|
1098 |
gs_glyph_data_free(&glyph_data, "psf_write_truetype_data");
|
|
|
1099 |
}
|
|
|
1100 |
|
|
|
1101 |
}
|
|
|
1102 |
/* Pad to numGlyphs + 1 entries (including the trailing entry). */
|
|
|
1103 |
for (; glyph_prev <= numGlyphs; ++glyph_prev)
|
|
|
1104 |
put_loca(s, offset, indexToLocFormat);
|
|
|
1105 |
put_pad(s, loca_length);
|
|
|
1106 |
|
|
|
1107 |
/* If necessary, write cmap, name, and OS/2. */
|
|
|
1108 |
|
|
|
1109 |
if (!have_cmap)
|
|
|
1110 |
write_cmap(s, font, TT_BIAS, 256, GS_MIN_GLYPH_INDEX + max_glyph,
|
|
|
1111 |
options, cmap_length);
|
|
|
1112 |
if (!have_name)
|
|
|
1113 |
write_name(s, &font_name);
|
|
|
1114 |
if (!have_OS_2)
|
|
|
1115 |
write_OS_2(s, font, TT_BIAS, 256);
|
|
|
1116 |
|
|
|
1117 |
/* If necessary, write [hv]mtx. */
|
|
|
1118 |
|
|
|
1119 |
if (generate_mtx)
|
|
|
1120 |
for (i = 0; i < 2; ++i)
|
|
|
1121 |
if (have_hvhea[i]) {
|
|
|
1122 |
write_mtx(s, pfont, &mtx[i], i);
|
|
|
1123 |
put_pad(s, mtx[i].length);
|
|
|
1124 |
}
|
|
|
1125 |
|
|
|
1126 |
/* If necessary, write post. */
|
|
|
1127 |
|
|
|
1128 |
if (!have_post) {
|
|
|
1129 |
if (options & WRITE_TRUETYPE_POST)
|
|
|
1130 |
write_post(s, font, &post);
|
|
|
1131 |
else {
|
|
|
1132 |
byte post_initial[32 + 2];
|
|
|
1133 |
|
|
|
1134 |
memset(post_initial, 0, 32);
|
|
|
1135 |
put_u32(post_initial, 0x00030000);
|
|
|
1136 |
stream_write(s, post_initial, 32);
|
|
|
1137 |
}
|
|
|
1138 |
}
|
|
|
1139 |
}
|
|
|
1140 |
|
|
|
1141 |
/* Write head. */
|
|
|
1142 |
|
|
|
1143 |
/****** CHECKSUM WAS NEVER COMPUTED ******/
|
|
|
1144 |
/*
|
|
|
1145 |
* The following nonsense is to avoid warnings about the constant
|
|
|
1146 |
* 0xb1b0afbaL being "unsigned in ANSI C, signed with -traditional".
|
|
|
1147 |
*/
|
|
|
1148 |
#if ARCH_SIZEOF_LONG > ARCH_SIZEOF_INT
|
|
|
1149 |
# define HEAD_MAGIC 0xb1b0afbaL
|
|
|
1150 |
#else
|
|
|
1151 |
# define HEAD_MAGIC ((ulong)~0x4e4f5045)
|
|
|
1152 |
#endif
|
|
|
1153 |
put_u32(head + 8, HEAD_MAGIC - file_checksum); /* per spec */
|
|
|
1154 |
#undef HEAD_MAGIC
|
|
|
1155 |
stream_write(s, head, 56);
|
|
|
1156 |
|
|
|
1157 |
return 0;
|
|
|
1158 |
}
|
|
|
1159 |
|
|
|
1160 |
/* Write a TrueType font. */
|
|
|
1161 |
int
|
|
|
1162 |
psf_write_truetype_font(stream *s, gs_font_type42 *pfont, int options,
|
|
|
1163 |
gs_glyph *orig_subset_glyphs, uint orig_subset_size,
|
|
|
1164 |
const gs_const_string *alt_font_name)
|
|
|
1165 |
{
|
|
|
1166 |
gs_font *const font = (gs_font *)pfont;
|
|
|
1167 |
psf_glyph_enum_t genum;
|
|
|
1168 |
gs_glyph subset_data[256 * MAX_COMPOSITE_PIECES];
|
|
|
1169 |
gs_glyph *subset_glyphs = orig_subset_glyphs;
|
|
|
1170 |
uint subset_size = orig_subset_size;
|
|
|
1171 |
|
|
|
1172 |
/* Sort the subset glyphs, if any. */
|
|
|
1173 |
|
|
|
1174 |
if (subset_glyphs) {
|
|
|
1175 |
/* Add the component glyphs for composites. */
|
|
|
1176 |
int code;
|
|
|
1177 |
|
|
|
1178 |
memcpy(subset_data, orig_subset_glyphs,
|
|
|
1179 |
sizeof(gs_glyph) * subset_size);
|
|
|
1180 |
subset_glyphs = subset_data;
|
|
|
1181 |
code = psf_add_subset_pieces(subset_glyphs, &subset_size,
|
|
|
1182 |
countof(subset_data),
|
|
|
1183 |
countof(subset_data),
|
|
|
1184 |
font);
|
|
|
1185 |
if (code < 0)
|
|
|
1186 |
return code;
|
|
|
1187 |
subset_size = psf_sort_glyphs(subset_glyphs, subset_size);
|
|
|
1188 |
}
|
|
|
1189 |
psf_enumerate_glyphs_begin(&genum, font, subset_glyphs,
|
|
|
1190 |
(subset_glyphs ? subset_size : 0),
|
|
|
1191 |
GLYPH_SPACE_INDEX);
|
|
|
1192 |
return psf_write_truetype_data(s, pfont, options & ~WRITE_TRUETYPE_CID,
|
|
|
1193 |
&genum, subset_glyphs != 0, alt_font_name);
|
|
|
1194 |
}
|
|
|
1195 |
/* Write a stripped TrueType font. */
|
|
|
1196 |
int
|
|
|
1197 |
psf_write_truetype_stripped(stream *s, gs_font_type42 *pfont)
|
|
|
1198 |
{
|
|
|
1199 |
psf_glyph_enum_t genum;
|
|
|
1200 |
byte no_subset = 0;
|
|
|
1201 |
|
|
|
1202 |
psf_enumerate_bits_begin(&genum, (gs_font *)pfont, &no_subset, 0,
|
|
|
1203 |
GLYPH_SPACE_INDEX);
|
|
|
1204 |
return psf_write_truetype_data(s, pfont, WRITE_TRUETYPE_STRIPPED,
|
|
|
1205 |
&genum, true, NULL);
|
|
|
1206 |
}
|
|
|
1207 |
|
|
|
1208 |
/* Write a CIDFontType 2 font. */
|
|
|
1209 |
int
|
|
|
1210 |
psf_write_cid2_font(stream *s, gs_font_cid2 *pfont, int options,
|
|
|
1211 |
const byte *subset_bits, uint subset_size,
|
|
|
1212 |
const gs_const_string *alt_font_name)
|
|
|
1213 |
{
|
|
|
1214 |
gs_font *const font = (gs_font *)pfont;
|
|
|
1215 |
psf_glyph_enum_t genum;
|
|
|
1216 |
|
|
|
1217 |
psf_enumerate_bits_begin(&genum, font, subset_bits,
|
|
|
1218 |
(subset_bits ? subset_size : 0),
|
|
|
1219 |
GLYPH_SPACE_INDEX);
|
|
|
1220 |
return psf_write_truetype_data(s, (gs_font_type42 *)font,
|
|
|
1221 |
options | WRITE_TRUETYPE_CID, &genum,
|
|
|
1222 |
subset_bits != 0, alt_font_name);
|
|
|
1223 |
}
|
|
|
1224 |
|
|
|
1225 |
/* Write a stripped CIDFontType 2 font. */
|
|
|
1226 |
int
|
|
|
1227 |
psf_write_cid2_stripped(stream *s, gs_font_cid2 *pfont)
|
|
|
1228 |
{
|
|
|
1229 |
gs_font *const font = (gs_font *)pfont;
|
|
|
1230 |
psf_glyph_enum_t genum;
|
|
|
1231 |
byte no_subset = 0;
|
|
|
1232 |
|
|
|
1233 |
psf_enumerate_bits_begin(&genum, font, &no_subset, 0,
|
|
|
1234 |
GLYPH_SPACE_INDEX);
|
|
|
1235 |
return psf_write_truetype_data(s, (gs_font_type42 *)font,
|
|
|
1236 |
WRITE_TRUETYPE_STRIPPED |
|
|
|
1237 |
WRITE_TRUETYPE_CID,
|
|
|
1238 |
&genum, true, NULL);
|
|
|
1239 |
}
|