/src/ghostpdl/devices/vector/gdevpsft.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Write an embedded TrueType font */ |
18 | | #include "memory_.h" |
19 | | #include <stdlib.h> /* for qsort */ |
20 | | #include <math.h> /* for floor */ |
21 | | #include "gx.h" |
22 | | #include "gscencs.h" |
23 | | #include "gserrors.h" |
24 | | #include "gsmatrix.h" |
25 | | #include "gsutil.h" |
26 | | #include "gxfcid.h" |
27 | | #include "gxfont.h" |
28 | | #include "gxfont42.h" |
29 | | #include "gxttf.h" |
30 | | #include "stream.h" |
31 | | #include "spprint.h" |
32 | | #include "gdevpsf.h" |
33 | | |
34 | | /* Internally used options */ |
35 | 80.4k | #define WRITE_TRUETYPE_STRIPPED 0x1000 /* internal */ |
36 | 89.5k | #define WRITE_TRUETYPE_CID 0x2000 /* internal */ |
37 | | |
38 | | #define MAX_COMPOSITE_PIECES 3 /* adhoc */ |
39 | | |
40 | | /* |
41 | | * The following are only for debugging. They force various format choices |
42 | | * in the output. The normal (non-debugging) values for all of these are |
43 | | * as indicated in the comments. |
44 | | * |
45 | | * Note that these options interact. Here is the complete list of settings |
46 | | * that make sense. |
47 | | 0 -1,0,1 N/A 0,1 0,1 |
48 | | 0xf000 -1 N/A 1 0,1 |
49 | | 0xf000 0,1 0,1 1 0,1 |
50 | | */ |
51 | | /* Define whether to use the 0xf000 character bias for generated tables. */ |
52 | 14.3k | #define TT_BIAS 0xf000 /* 0xf000 */ |
53 | | /* Define whether to use cmap format 6 never(-1), sometimes(0), always(1). */ |
54 | | #define TT_FORCE_CMAP_6 0 /* 0 */ |
55 | | /* Define whether to use the bias for the cmap format 6 "first code". */ |
56 | | #define TT_BIAS_CMAP_6 0 /* 0 */ |
57 | | /* Define whether to generate an OS/2 table if none is supplied. */ |
58 | | #define TT_GENERATE_OS_2 1 /* 1 */ |
59 | | /* Define whether to adjust the OS/2 range bits. */ |
60 | | #define TT_ADJUST_OS_2 1 /* 1 */ |
61 | | /* |
62 | | * End of options. |
63 | | */ |
64 | | |
65 | | /* ---------------- Utilities ---------------- */ |
66 | | |
67 | | /* Pad to a multiple of 4 bytes. */ |
68 | | static void |
69 | | put_pad(stream *s, uint length) |
70 | 398k | { |
71 | 398k | static const byte pad_to_4[3] = {0, 0, 0}; |
72 | | |
73 | 398k | stream_write(s, pad_to_4, (uint)(-(int)length & 3)); |
74 | 398k | } |
75 | | |
76 | | /* Put short and long values on a stream. */ |
77 | | static void |
78 | | put_ushort(stream *s, uint v) |
79 | 20.6M | { |
80 | 20.6M | stream_putc(s, (byte)(v >> 8)); |
81 | 20.6M | stream_putc(s, (byte)v); |
82 | 20.6M | } |
83 | | static void |
84 | | put_short(stream *s, short v) |
85 | 24.2M | { |
86 | 24.2M | stream_putc(s, (byte)(v >> 8)); |
87 | 24.2M | stream_putc(s, (byte)v); |
88 | 24.2M | } |
89 | | static void |
90 | | put_ulong(stream *s, ulong v) |
91 | 0 | { |
92 | 0 | put_ushort(s, (uint)(v >> 16)); |
93 | 0 | put_ushort(s, (uint)v); |
94 | 0 | } |
95 | | static void |
96 | | put_loca(stream *s, ulong offset, int indexToLocFormat) |
97 | 20.5M | { |
98 | 20.5M | if (indexToLocFormat) |
99 | 0 | put_ulong(s, offset); |
100 | 20.5M | else |
101 | 20.5M | put_ushort(s, (uint)(offset >> 1)); |
102 | 20.5M | } |
103 | | |
104 | | /* Get or put 2- or 4-byte quantities from/into a table. */ |
105 | | #define U8(p) ((uint)((p)[0])) |
106 | | #define S8(p) (int)((U8(p) ^ 0x80) - 0x80) |
107 | 1.92M | #define U16(p) (((uint)((p)[0]) << 8) + (p)[1]) |
108 | | #define S16(p) (int)((U16(p) ^ 0x8000) - 0x8000) |
109 | 5.76M | #define u32(p) get_u32_msb(p) |
110 | | static void |
111 | | put_u16(byte *p, uint v) |
112 | 3.75M | { |
113 | 3.75M | p[0] = (byte)(v >> 8); |
114 | 3.75M | p[1] = (byte)v; |
115 | 3.75M | } |
116 | | static void |
117 | | put_u32(byte *p, ulong v) |
118 | 619k | { |
119 | 619k | put_u16(p, (ushort)(v >> 16)); |
120 | 619k | put_u16(p + 2, (ushort)v); |
121 | 619k | } |
122 | | static ulong |
123 | | put_table(byte tab[16], const char *tname, ulong checksum, ulong offset, |
124 | | uint length) |
125 | 68.8k | { |
126 | 68.8k | memcpy(tab, (const byte *)tname, 4); |
127 | 68.8k | put_u32(tab + 4, checksum); |
128 | 68.8k | put_u32(tab + 8, offset + 0x40000000); |
129 | 68.8k | put_u32(tab + 12, (ulong)length); |
130 | 68.8k | return offset + round_up(length, 4); |
131 | 68.8k | } |
132 | | |
133 | | /* Write one range of a TrueType font. */ |
134 | | static int |
135 | | write_range(stream *s, gs_font_type42 *pfont, ulong start, uint length) |
136 | 368k | { |
137 | 368k | ulong base = start, size = length; |
138 | | |
139 | 368k | if_debug3m('l', s->memory, "[l]write_range pos = %"PRId64", start = %lu, length = %u\n", |
140 | 368k | stell(s), start, length); |
141 | 727k | while (size > 0) { |
142 | 368k | const byte *ptr; |
143 | 368k | int code; |
144 | | |
145 | 368k | code = pfont->data.string_proc(pfont, base, size, &ptr); |
146 | 368k | if (code < 0) |
147 | 9.51k | return code; |
148 | 359k | if (!code) |
149 | 359k | code = size; |
150 | 359k | stream_write(s, ptr, code); |
151 | 359k | base += code; |
152 | 359k | size -= code; |
153 | 359k | } |
154 | 359k | return 0; |
155 | 368k | } |
156 | | |
157 | | /* |
158 | | * Determine the Macintosh glyph number for a given character, if any. |
159 | | * If no glyph can be found, return -1 and store the name in *pstr. |
160 | | */ |
161 | | static int |
162 | | mac_glyph_index(gs_font *font, int ch, gs_const_string *pstr, int *index) |
163 | 0 | { |
164 | 0 | gs_glyph glyph = font->procs.encode_char(font, (gs_char)ch, |
165 | 0 | GLYPH_SPACE_NAME); |
166 | 0 | int code; |
167 | |
|
168 | 0 | if (glyph == GS_NO_GLYPH) { |
169 | 0 | *index = 0; |
170 | 0 | return 0; /* .notdef */ |
171 | 0 | } |
172 | 0 | code = font->procs.glyph_name(font, glyph, pstr); |
173 | 0 | if (code < 0) |
174 | 0 | return code; |
175 | 0 | if (glyph < GS_MIN_CID_GLYPH) { |
176 | 0 | gs_char mac_char; |
177 | 0 | gs_glyph mac_glyph; |
178 | 0 | gs_const_string mstr; |
179 | | |
180 | | /* Look (not very hard) for a match in the Mac glyph space. */ |
181 | 0 | if (ch >= 32 && ch <= 126) |
182 | 0 | mac_char = ch - 29; |
183 | 0 | else if (ch >= 128 && ch <= 255) |
184 | 0 | mac_char = ch - 30; |
185 | 0 | else { |
186 | 0 | *index = -1; |
187 | 0 | return 0; |
188 | 0 | } |
189 | 0 | mac_glyph = gs_c_known_encode(mac_char, ENCODING_INDEX_MACGLYPH); |
190 | 0 | if (mac_glyph == GS_NO_GLYPH) { |
191 | 0 | *index = -1; |
192 | 0 | return 0; |
193 | 0 | } |
194 | 0 | code = gs_c_glyph_name(mac_glyph, &mstr); |
195 | 0 | if (code < 0) |
196 | 0 | return code; |
197 | 0 | if (!bytes_compare(pstr->data, pstr->size, mstr.data, mstr.size)) { |
198 | 0 | *index = (int)mac_char; |
199 | 0 | return 0; |
200 | 0 | } |
201 | 0 | } |
202 | 0 | *index = -1; |
203 | 0 | return 0; |
204 | 0 | } |
205 | | |
206 | | /* ---------------- Individual tables ---------------- */ |
207 | | |
208 | | /* ------ cmap ------ */ |
209 | | |
210 | | /* Write a generated cmap table. */ |
211 | | static const byte cmap_initial_0[] = { |
212 | | 0, 0, /* table version # = 0 */ |
213 | | 0, 2, /* # of encoding tables = 2 */ |
214 | | |
215 | | /* First table, Macintosh */ |
216 | | 0, 1, /* platform ID = Macintosh */ |
217 | | 0, 0, /* platform encoding ID = ??? */ |
218 | | 0, 0, 0, 4+8+8, /* offset to table start */ |
219 | | /* Second table, Windows */ |
220 | | 0, 3, /* platform ID = Microsoft */ |
221 | | 0, 0, /* platform encoding ID = unknown */ |
222 | | 0, 0, 1, 4+8+8+6, /* offset to table start */ |
223 | | |
224 | | /* Start of Macintosh format 0 table */ |
225 | | 0, 0, /* format = 0, byte encoding table */ |
226 | | 1, 6, /* length */ |
227 | | 0, 0 /* version number */ |
228 | | }; |
229 | | static const byte cmap_initial_6[] = { |
230 | | 0, 0, /* table version # = 0 */ |
231 | | 0, 2, /* # of encoding tables = 2 */ |
232 | | |
233 | | /* First table, Macintosh */ |
234 | | 0, 1, /* platform ID = Macintosh */ |
235 | | 0, 0, /* platform encoding ID = ??? */ |
236 | | 0, 0, 0, 4+8+8, /* offset to table start */ |
237 | | /* Second table, Windows */ |
238 | | 0, 3, /* platform ID = Microsoft */ |
239 | | 0, 0, /* platform encoding ID = unknown */ |
240 | | 0, 0, 0, 4+8+8+10, /* offset to table start */ |
241 | | /* *VARIABLE*, add 2 x # of entries */ |
242 | | |
243 | | /* Start of Macintosh format 6 table */ |
244 | | 0, 6, /* format = 6, trimmed table mapping */ |
245 | | 0, 10, /* length *VARIABLE*, add 2 x # of entries */ |
246 | | 0, 0, /* version number */ |
247 | | 0, 0, /* first character code */ |
248 | | 0, 0 /* # of entries *VARIABLE* */ |
249 | | }; |
250 | | static const byte cmap_unicode_initial_6[] = { |
251 | | 0, 0, /* table version # = 0 */ |
252 | | 0, 2, /* # of encoding tables = 2 */ |
253 | | |
254 | | /* First table, Macintosh */ |
255 | | 0, 1, /* platform ID = Macintosh */ |
256 | | 0, 0, /* platform encoding ID = ??? */ |
257 | | 0, 0, 0, 4+8+8, /* offset to table start */ |
258 | | /* Second table, Windows */ |
259 | | 0, 3, /* platform ID = Microsoft */ |
260 | | 0, 1, /* platform encoding ID = Unicode */ |
261 | | 0, 0, 0, 4+8+8+10, /* offset to table start */ |
262 | | /* *VARIABLE*, add 2 x # of entries */ |
263 | | |
264 | | /* Start of Macintosh format 6 table */ |
265 | | 0, 6, /* format = 6, trimmed table mapping */ |
266 | | 0, 10, /* length *VARIABLE*, add 2 x # of entries */ |
267 | | 0, 0, /* version number */ |
268 | | 0, 0, /* first character code */ |
269 | | 0, 0 /* # of entries *VARIABLE* */ |
270 | | }; |
271 | | static const byte cmap_initial_4[] = { |
272 | | 0, 0, /* table version # = 0 */ |
273 | | 0, 1, /* # of encoding tables = 2 */ |
274 | | |
275 | | /* Single table, Windows */ |
276 | | 0, 3, /* platform ID = Microsoft */ |
277 | | 0, 0, /* platform encoding ID = unknown */ |
278 | | 0, 0, 0, 4+8 /* offset to table start */ |
279 | | }; |
280 | | static const byte cmap_sub_initial[] = { |
281 | | 0, 4, /* format = 4, segment mapping */ |
282 | | 0, 32, /* length ** VARIABLE, add 2 x # of glyphs ** */ |
283 | | 0, 0, /* version # */ |
284 | | 0, 4, /* 2 x segCount */ |
285 | | 0, 4, /* searchRange = 2 x 2 ^ floor(log2(segCount)) */ |
286 | | 0, 1, /* floor(log2(segCount)) */ |
287 | | 0, 0, /* 2 x segCount - searchRange */ |
288 | | |
289 | | 0, 0, /* endCount[0] **VARIABLE** */ |
290 | | 255, 255, /* endCount[1] */ |
291 | | 0, 0, /* reservedPad */ |
292 | | 0, 0, /* startCount[0] **VARIABLE** */ |
293 | | 255, 255, /* startCount[1] */ |
294 | | 0, 0, /* idDelta[0] */ |
295 | | 0, 1, /* idDelta[1] */ |
296 | | 0, 4, /* idRangeOffset[0] */ |
297 | | 0, 0 /* idRangeOffset[1] */ |
298 | | }; |
299 | | /* |
300 | | * The following nonsense is required because C defines sizeof() |
301 | | * inconsistently. |
302 | | */ |
303 | 8.88k | #define CMAP_ENTRIES_SIZE (256 * 2) |
304 | | static void |
305 | | write_cmap_0(stream *s, byte* entries /*[CMAP_ENTRIES_SIZE]*/, uint num_glyphs) |
306 | 8.88k | { |
307 | 8.88k | int i; |
308 | | |
309 | 8.88k | if (CMAP_ENTRIES_SIZE - 2 * num_glyphs>0) |
310 | 0 | memset(entries + 2 * num_glyphs, 0, CMAP_ENTRIES_SIZE - 2 * num_glyphs); |
311 | 8.88k | stream_write(s, cmap_initial_0, sizeof(cmap_initial_0)); |
312 | 2.28M | for (i = 0; i <= 0xff; ++i) |
313 | 2.27M | sputc(s, (byte)entries[2 * i + 1]); |
314 | 8.88k | } |
315 | | static void |
316 | | write_cmap_6(stream *s, byte *entries /*[CMAP_ENTRIES_SIZE]*/, uint first_code, |
317 | | uint first_entry, uint num_entries) |
318 | 308 | { |
319 | 308 | byte cmap_data[sizeof(cmap_initial_6)]; |
320 | | |
321 | 308 | memcpy(cmap_data, cmap_initial_6, sizeof(cmap_initial_6)); |
322 | 308 | put_u16(cmap_data + 18, |
323 | 308 | U16(cmap_data + 18) + num_entries * 2); /* offset */ |
324 | 308 | put_u16(cmap_data + 22, |
325 | 308 | U16(cmap_data + 22) + num_entries * 2); /* length */ |
326 | 308 | put_u16(cmap_data + 26, |
327 | | #if TT_BIAS_CMAP_6 |
328 | | first_code + |
329 | | #endif |
330 | 308 | first_entry); |
331 | 308 | put_u16(cmap_data + 28, num_entries); |
332 | 308 | stream_write(s, cmap_data, sizeof(cmap_data)); |
333 | 308 | stream_write(s, entries + first_entry * 2, num_entries * 2); |
334 | 308 | } |
335 | | static void write_unicode_cmap_6(stream *s, byte *entries, uint first_code, |
336 | | uint first_entry, uint num_entries) |
337 | 0 | { |
338 | 0 | byte cmap_data[sizeof(cmap_unicode_initial_6)]; |
339 | |
|
340 | 0 | memcpy(cmap_data, cmap_unicode_initial_6, sizeof(cmap_unicode_initial_6)); |
341 | 0 | put_u16(cmap_data + 18, |
342 | 0 | U16(cmap_data + 18) + num_entries * 2); /* offset */ |
343 | 0 | put_u16(cmap_data + 22, |
344 | 0 | U16(cmap_data + 22) + num_entries * 2); /* length */ |
345 | 0 | put_u16(cmap_data + 26, first_entry); |
346 | 0 | put_u16(cmap_data + 28, num_entries); |
347 | 0 | stream_write(s, cmap_data, sizeof(cmap_data)); |
348 | 0 | stream_write(s, entries + first_entry * 2, num_entries * 2); |
349 | 0 | } |
350 | | static void |
351 | | write_cmap(stream *s, gs_font *font, uint first_code, int num_glyphs, |
352 | | gs_glyph max_glyph, int options, uint cmap_length) |
353 | 9.59k | { |
354 | 9.59k | byte cmap_sub[sizeof(cmap_sub_initial)]; |
355 | 9.59k | byte entries[CMAP_ENTRIES_SIZE]; |
356 | 9.59k | int first_entry = 0, end_entry = num_glyphs; |
357 | 9.59k | bool can_use_trimmed = !(options & WRITE_TRUETYPE_NO_TRIMMED_TABLE); |
358 | 9.59k | uint merge = 0; |
359 | 9.59k | uint num_entries; |
360 | 9.59k | int i; |
361 | | |
362 | | /* Collect the table entries. */ |
363 | | |
364 | 2.46M | for (i = 0; i < num_glyphs; ++i) { |
365 | 2.45M | gs_glyph glyph = |
366 | 2.45M | font->procs.encode_char(font, (gs_char)i, GLYPH_SPACE_INDEX); |
367 | 2.45M | uint glyph_index; |
368 | | |
369 | 2.45M | if (glyph == GS_NO_GLYPH || glyph < GS_MIN_GLYPH_INDEX || |
370 | 2.45M | glyph > max_glyph |
371 | 2.45M | ) |
372 | 2.23M | glyph = GS_MIN_GLYPH_INDEX; |
373 | 2.45M | glyph_index = (uint)(glyph - GS_MIN_GLYPH_INDEX); |
374 | 2.45M | merge |= glyph_index; |
375 | 2.45M | put_u16(entries + 2 * i, glyph_index); |
376 | 2.45M | } |
377 | 1.46M | while (end_entry > first_entry && !U16(entries + 2 * end_entry - 2)) |
378 | 1.45M | --end_entry; |
379 | 360k | while (first_entry < end_entry && !U16(entries + 2 * first_entry)) |
380 | 350k | ++first_entry; |
381 | 9.59k | num_entries = end_entry - first_entry; |
382 | | |
383 | | /* Write the table header and Macintosh sub-table (if any). */ |
384 | | |
385 | 9.59k | if (options & WRITE_TRUETYPE_UNICODE_CMAP) { |
386 | 0 | write_unicode_cmap_6(s, entries, first_code, first_entry, num_entries); |
387 | | |
388 | | /* Write the Windows sub-table. */ |
389 | 0 | memcpy(cmap_sub, cmap_sub_initial, sizeof(cmap_sub_initial)); |
390 | 0 | put_u16(cmap_sub + 2, U16(cmap_sub + 2) + num_entries * 2); /* length */ |
391 | 0 | put_u16(cmap_sub + 14, end_entry - 1); /* endCount[0] */ |
392 | 0 | put_u16(cmap_sub + 20, first_entry); /* startCount[0] */ |
393 | 0 | stream_write(s, cmap_sub, sizeof(cmap_sub)); |
394 | 0 | stream_write(s, entries + first_entry * 2, num_entries * 2); |
395 | 0 | put_pad(s, cmap_length); |
396 | 0 | return; |
397 | 0 | } |
398 | | #if TT_FORCE_CMAP_6 > 0 |
399 | | /* Always use format 6. */ |
400 | | write_cmap_6(s, entries, first_code, first_entry, num_entries); |
401 | | #else |
402 | | # if TT_FORCE_CMAP_6 < 0 |
403 | | /* Never use format 6. Use format 0 if possible. */ |
404 | | if (merge == (byte)merge) |
405 | | write_cmap_0(s, entries, num_glyphs); |
406 | | else |
407 | | # else /* TT_FORCE_CMAP == 0 */ |
408 | | /* |
409 | | * Use format 0 if possible and (economical or format 6 disallowed), |
410 | | * otherwise format 6 if allowed. |
411 | | */ |
412 | 9.59k | if (merge == (byte)merge && (num_entries <= 127 || !can_use_trimmed)) |
413 | 8.88k | write_cmap_0(s, entries, num_glyphs); |
414 | 716 | else if (can_use_trimmed) |
415 | 308 | write_cmap_6(s, entries, first_code, first_entry, num_entries); |
416 | 408 | else |
417 | 408 | # endif |
418 | 408 | { |
419 | | /* |
420 | | * Punt. Acrobat Reader 3 can't handle any other Mac table format. |
421 | | * (AR3 for Linux doesn't seem to be able to handle Windows format, |
422 | | * either, but maybe AR3 for Windows can.) |
423 | | */ |
424 | 408 | stream_write(s, cmap_initial_4, sizeof(cmap_initial_4)); |
425 | 408 | } |
426 | 9.59k | #endif |
427 | | |
428 | | /* Write the Windows sub-table. */ |
429 | | |
430 | 9.59k | memcpy(cmap_sub, cmap_sub_initial, sizeof(cmap_sub_initial)); |
431 | 9.59k | put_u16(cmap_sub + 2, U16(cmap_sub + 2) + num_entries * 2); /* length */ |
432 | 9.59k | put_u16(cmap_sub + 14, first_code + end_entry - 1); /* endCount[0] */ |
433 | 9.59k | put_u16(cmap_sub + 20, first_code + first_entry); /* startCount[0] */ |
434 | 9.59k | stream_write(s, cmap_sub, sizeof(cmap_sub)); |
435 | 9.59k | stream_write(s, entries + first_entry * 2, num_entries * 2); |
436 | 9.59k | put_pad(s, cmap_length); |
437 | 9.59k | } |
438 | | static uint |
439 | | size_cmap(gs_font *font, uint first_code, int num_glyphs, gs_glyph max_glyph, |
440 | | int options) |
441 | 4.79k | { |
442 | 4.79k | stream poss; |
443 | | |
444 | 4.79k | s_init(&poss, NULL); |
445 | 4.79k | swrite_position_only(&poss); |
446 | 4.79k | write_cmap(&poss, font, first_code, num_glyphs, max_glyph, options, 0); |
447 | 4.79k | return stell(&poss); |
448 | 4.79k | } |
449 | | |
450 | | /* ------ hmtx/vmtx ------ */ |
451 | | |
452 | | /* We must include mtx data for every single glyph, even if we don't |
453 | | * actually write the glyph data. If we don't, the font will be invalid (cf bug 697376) |
454 | | * We also must not simply copy the table from the original font, because its possible |
455 | | * that we are combining two different fonts, and the metrics in each font may not |
456 | | * be the same (or at least, not in the same position) cf bug 700099. |
457 | | * Originally we only wrote the metrics for the glyphs we copy, then we disabled |
458 | | * generat_mtx so that we copied the table. This solution; generating all the metrics |
459 | | * we need and dummies for the glyphs we don't actually embed, works best so far. |
460 | | */ |
461 | | static void |
462 | | write_mtx(stream *s, gs_font_type42 *pfont, const gs_type42_mtx_t *pmtx, |
463 | | int wmode) |
464 | 5.09k | { |
465 | 5.09k | uint num_metrics = pmtx->numMetrics; |
466 | 5.09k | uint len = num_metrics * 4; |
467 | 5.09k | double factor = (double)pfont->data.unitsPerEm * (wmode ? -1 : 1); |
468 | 5.09k | float sbw[4]; |
469 | 5.09k | uint i; |
470 | | |
471 | 5.09k | sbw[0] = sbw[1] = sbw[2] = sbw[3] = 0; /* in case of failures */ |
472 | 2.04M | for (i = 0; i < pmtx->numMetrics; ++i) { |
473 | 2.04M | float f; |
474 | 2.04M | DISCARD(pfont->data.get_metrics(pfont, i, wmode, sbw)); |
475 | | /* the temporary assignment to a float is necessary for AIX else the result is always 0 if sbw[] < 0 |
476 | | this happens even with gcc and I'm not sure why it happens at all nor why only on AIX */ |
477 | 2.04M | f = (float) (sbw[wmode + 2] * factor); /* width */ |
478 | 2.04M | put_short(s, (short) floor(f + 0.5)); |
479 | 2.04M | f = (float) (sbw[wmode] * factor); /* lsb, may be <0 */ |
480 | 2.04M | put_short(s, (short) floor(f + 0.5)); |
481 | 2.04M | } |
482 | 20.1M | for (; len < pmtx->length; ++i, len += 2) { |
483 | 20.1M | float f; |
484 | 20.1M | DISCARD(pfont->data.get_metrics(pfont, i, wmode, sbw)); |
485 | 20.1M | f = (float) (sbw[wmode] * factor); /* lsb, may be <0 */ |
486 | 20.1M | put_short(s, (short) floor(f + 0.5)); |
487 | 20.1M | } |
488 | 5.09k | } |
489 | | |
490 | | /* Compute the metrics from the glyph_info. */ |
491 | | static uint |
492 | | size_mtx(gs_font_type42 *pfont, gs_type42_mtx_t *pmtx, uint max_glyph, uint numGlyphs, |
493 | | int wmode) |
494 | 5.09k | { |
495 | 5.09k | int prev_width = min_int; |
496 | 5.09k | uint last_width = 0; /* pacify compilers */ |
497 | 5.09k | double factor = pfont->data.unitsPerEm * (wmode ? -1 : 1); |
498 | 5.09k | uint i; |
499 | | |
500 | 3.70M | for (i = 0; i <= max_glyph; ++i) { |
501 | 3.69M | float sbw[4]; |
502 | 3.69M | int code = pfont->data.get_metrics(pfont, i, wmode, sbw); |
503 | 3.69M | int width; |
504 | | |
505 | 3.69M | if (code < 0) |
506 | 3.57M | continue; |
507 | 117k | width = (int)(sbw[wmode + 2] * factor + 0.5); |
508 | 117k | if (width != prev_width) |
509 | 89.7k | prev_width = width, last_width = i; |
510 | 117k | } |
511 | 5.09k | pmtx->numMetrics = last_width + 1; |
512 | 5.09k | pmtx->length = pmtx->numMetrics * 4 + (max_glyph - last_width) * 2; |
513 | 5.09k | pmtx->length += (numGlyphs - pmtx->numMetrics) * 2; |
514 | 5.09k | return pmtx->length; |
515 | 5.09k | } |
516 | | |
517 | | /* ------ name ------ */ |
518 | | |
519 | | /* Write a generated name table. */ |
520 | | static const byte name_initial[] = { |
521 | | 0, 0, /* format */ |
522 | | 0, 1, /* # of records = 1 */ |
523 | | 0, 18, /* start of string storage */ |
524 | | |
525 | | 0, 2, /* platform ID = ISO */ |
526 | | 0, 2, /* encoding ID = ISO 8859-1 */ |
527 | | 0, 0, /* language ID (none) */ |
528 | | 0, 6, /* name ID = PostScript name */ |
529 | | 0, 0, /* length *VARIABLE* */ |
530 | | 0, 0 /* start of string within string storage */ |
531 | | }; |
532 | | static uint |
533 | | size_name(const gs_const_string *font_name) |
534 | 216 | { |
535 | 216 | return sizeof(name_initial) + font_name->size; |
536 | 216 | } |
537 | | static void |
538 | | write_name(stream *s, const gs_const_string *font_name) |
539 | 108 | { |
540 | 108 | byte name_bytes[sizeof(name_initial)]; |
541 | | |
542 | 108 | memcpy(name_bytes, name_initial, sizeof(name_initial)); |
543 | 108 | put_u16(name_bytes + 14, font_name->size); |
544 | 108 | stream_write(s, name_bytes, sizeof(name_bytes)); |
545 | 108 | stream_write(s, font_name->data, font_name->size); |
546 | 108 | put_pad(s, size_name(font_name)); |
547 | 108 | } |
548 | | |
549 | | /* ------ OS/2 ------ */ |
550 | | |
551 | | /* Write a generated OS/2 table. */ |
552 | 42.7k | #define OS_2_LENGTH1 offset_of(ttf_OS_2_t, sxHeight[0]) /* OS/2 version 1. */ |
553 | | #define OS_2_LENGTH2 offset_of(ttf_OS_2_t, usLowerOpticalPointSize[0]) /* OS/2 version 2. */ |
554 | 28.4k | #define OS_2_LENGTH5 sizeof(ttf_OS_2_t) /* OS/2 version 5 (OpenType 1.7) */ |
555 | | |
556 | | static void |
557 | | update_OS_2(ttf_OS_2_t *pos2, uint first_glyph, int num_glyphs) |
558 | 4.79k | { |
559 | 4.79k | put_u16(pos2->usFirstCharIndex, first_glyph); |
560 | 4.79k | put_u16(pos2->usLastCharIndex, first_glyph + num_glyphs - 1); |
561 | 4.79k | #if TT_ADJUST_OS_2 |
562 | 4.79k | if (first_glyph >= 0xf000) { |
563 | | /* This font is being treated as a symbolic font. */ |
564 | 4.79k | memset(pos2->ulUnicodeRanges, 0, sizeof(pos2->ulUnicodeRanges)); |
565 | 4.79k | pos2->ulUnicodeRanges[7] = 8; /* bit 60, private use range */ |
566 | 4.79k | memset(pos2->ulCodePageRanges, 0, sizeof(pos2->ulCodePageRanges)); |
567 | 4.79k | pos2->ulCodePageRanges[3] = 1; /* bit 31, symbolic */ |
568 | 4.79k | } |
569 | 4.79k | #endif |
570 | 4.79k | } |
571 | | static void |
572 | | write_OS_2(stream *s, gs_font *font, uint first_glyph, int num_glyphs) |
573 | 4.79k | { |
574 | 4.79k | ttf_OS_2_t os2; |
575 | 4.79k | gs_font_info_t info; |
576 | 4.79k | int code; |
577 | | |
578 | | /* |
579 | | * We don't bother to set most of the fields. The really important |
580 | | * ones, which affect character mapping, are usFirst/LastCharIndex. |
581 | | * We also need to set usWeightClass and usWidthClass to avoid |
582 | | * crashing ttfdump. Version 1 86-byte structure has all the fields |
583 | | * we need. |
584 | | */ |
585 | 4.79k | memset(&os2, 0, sizeof(os2)); |
586 | 4.79k | put_u16(os2.version, 1); |
587 | 4.79k | put_u16(os2.usWeightClass, 400); /* Normal */ |
588 | 4.79k | put_u16(os2.usWidthClass, 5); /* Normal */ |
589 | 4.79k | update_OS_2(&os2, first_glyph, num_glyphs); |
590 | | |
591 | | /* |
592 | | * We should also preserve the licensed embedding rights, to prevent |
593 | | * 'laundering' a TrueType font. These can be non-zero even when embedding is permitted. |
594 | | */ |
595 | 4.79k | memset(&info, 0x00, sizeof(gs_font_info_t)); |
596 | 4.79k | code = font->procs.font_info(font, NULL, FONT_INFO_EMBEDDING_RIGHTS, &info); |
597 | 4.79k | if (code == 0 && (info.members & FONT_INFO_EMBEDDING_RIGHTS)) { |
598 | 2.71k | put_u16(os2.fsType, info.EmbeddingRights); |
599 | 2.71k | } |
600 | | |
601 | 4.79k | stream_write(s, &os2, offset_of(ttf_OS_2_t, sxHeight[0])); |
602 | 4.79k | put_pad(s, offset_of(ttf_OS_2_t, sxHeight[0])); |
603 | 4.79k | } |
604 | | |
605 | | /* ------ post ------ */ |
606 | | |
607 | | /* Construct and then write the post table. */ |
608 | | typedef struct post_glyph_s { |
609 | | byte char_index; |
610 | | byte size; |
611 | | ushort glyph_index; |
612 | | } post_glyph_t; |
613 | | static int |
614 | | compare_post_glyphs(const void *pg1, const void *pg2) |
615 | 0 | { |
616 | 0 | gs_glyph g1 = ((const post_glyph_t *)pg1)->glyph_index, |
617 | 0 | g2 = ((const post_glyph_t *)pg2)->glyph_index; |
618 | |
|
619 | 0 | return (g1 < g2 ? -1 : g1 > g2 ? 1 : 0); |
620 | 0 | } |
621 | | typedef struct post_s { |
622 | | post_glyph_t glyphs[256 + 1]; |
623 | | int count, glyph_count; |
624 | | uint length; |
625 | | } post_t; |
626 | | |
627 | | /* |
628 | | * If necessary, compute the length of the post table. Note that we |
629 | | * only generate post entries for characters in the Encoding. |
630 | | */ |
631 | | static int |
632 | | compute_post(gs_font *font, post_t *post) |
633 | 0 | { |
634 | 0 | int i; |
635 | |
|
636 | 0 | for (i = 0, post->length = 32 + 2; i <= 255; ++i) { |
637 | 0 | gs_const_string str; |
638 | 0 | gs_glyph glyph = font->procs.encode_char(font, (gs_char)i, |
639 | 0 | GLYPH_SPACE_INDEX); |
640 | 0 | int mac_index; |
641 | |
|
642 | 0 | int code = mac_glyph_index(font, i, &str, &mac_index); |
643 | 0 | if (code < 0) |
644 | 0 | return code; |
645 | 0 | if (mac_index != 0) { |
646 | 0 | post->glyphs[post->count].char_index = i; |
647 | 0 | post->glyphs[post->count].size = |
648 | 0 | (mac_index < 0 ? str.size + 1 : 0); |
649 | 0 | post->glyphs[post->count].glyph_index = glyph - GS_MIN_GLYPH_INDEX; |
650 | 0 | post->count++; |
651 | 0 | } |
652 | 0 | } |
653 | 0 | if (post->count) { |
654 | 0 | int j; |
655 | |
|
656 | 0 | qsort(post->glyphs, post->count, sizeof(post->glyphs[0]), |
657 | 0 | compare_post_glyphs); |
658 | | /* Eliminate duplicate references to the same glyph. */ |
659 | 0 | for (i = j = 0; i < post->count; ++i) { |
660 | 0 | if (i == 0 || |
661 | 0 | post->glyphs[i].glyph_index != |
662 | 0 | post->glyphs[i - 1].glyph_index |
663 | 0 | ) { |
664 | 0 | post->length += post->glyphs[i].size; |
665 | 0 | post->glyphs[j++] = post->glyphs[i]; |
666 | 0 | } |
667 | 0 | } |
668 | 0 | post->count = j; |
669 | 0 | post->glyph_count = post->glyphs[post->count - 1].glyph_index + 1; |
670 | 0 | } |
671 | 0 | post->length += post->glyph_count * 2; |
672 | 0 | return 0; |
673 | 0 | } |
674 | | |
675 | | /* Write the post table */ |
676 | | static int |
677 | | write_post(stream *s, gs_font *font, post_t *post) |
678 | 0 | { |
679 | 0 | byte post_initial[32 + 2]; |
680 | 0 | uint name_index; |
681 | 0 | uint glyph_index; |
682 | 0 | int i; |
683 | |
|
684 | 0 | memset(post_initial, 0, 32); |
685 | 0 | put_u32(post_initial, 0x00020000); |
686 | 0 | put_u16(post_initial + 32, post->glyph_count); |
687 | 0 | stream_write(s, post_initial, sizeof(post_initial)); |
688 | | |
689 | | /* Write the name index table. */ |
690 | |
|
691 | 0 | for (i = 0, name_index = 258, glyph_index = 0; i < post->count; ++i) { |
692 | 0 | gs_const_string str; |
693 | 0 | int ch = post->glyphs[i].char_index; |
694 | 0 | int mac_index; |
695 | 0 | int code = mac_glyph_index(font, ch, &str, &mac_index); |
696 | |
|
697 | 0 | if (code < 0) |
698 | 0 | return code; |
699 | 0 | for (; glyph_index < post->glyphs[i].glyph_index; ++glyph_index) |
700 | 0 | put_ushort(s, 0); |
701 | 0 | glyph_index++; |
702 | 0 | if (mac_index >= 0) |
703 | 0 | put_ushort(s, mac_index); |
704 | 0 | else { |
705 | 0 | put_ushort(s, name_index); |
706 | 0 | name_index++; |
707 | 0 | } |
708 | 0 | } |
709 | | |
710 | | /* Write the string names of the glyphs. */ |
711 | | |
712 | 0 | for (i = 0; i < post->count; ++i) { |
713 | 0 | gs_const_string str; |
714 | 0 | int ch = post->glyphs[i].char_index; |
715 | 0 | int mac_index; |
716 | 0 | int code = mac_glyph_index(font, ch, &str, &mac_index); |
717 | |
|
718 | 0 | if (code < 0) |
719 | 0 | return code; |
720 | 0 | if (mac_index < 0) { |
721 | 0 | spputc(s, (byte)str.size); |
722 | 0 | stream_write(s, str.data, str.size); |
723 | 0 | } |
724 | 0 | } |
725 | 0 | put_pad(s, post->length); |
726 | 0 | return 0; |
727 | 0 | } |
728 | | |
729 | | static inline bool check_position(const gs_memory_t *mem, gs_offset_t pos1, gs_offset_t pos2) |
730 | 68.8k | { |
731 | 68.8k | if (pos1 == pos2) |
732 | 59.7k | return false; |
733 | 9.09k | emprintf2(mem, |
734 | 9.09k | "Actual TT subtable offset %"PRId64" differs from one in the TT header %"PRId64".\n", |
735 | 9.09k | pos1, |
736 | 9.09k | pos2); |
737 | 9.09k | return true; |
738 | 68.8k | } |
739 | | |
740 | | static void remove_table(byte *tables, char *tag, uint *numTables) |
741 | 0 | { |
742 | | /* Not a high performance implementation because it is called seldom. */ |
743 | 0 | int i; |
744 | |
|
745 | 0 | for (i = 0; i < *numTables;) { |
746 | 0 | byte *tab = tables + i * 16; |
747 | |
|
748 | 0 | if (!memcmp(tab, tag, 4)) { |
749 | 0 | memmove(tab, tab + 16, 16 * (*numTables - i - 1)); |
750 | 0 | --*numTables; |
751 | 0 | } else |
752 | 0 | ++i; |
753 | 0 | } |
754 | 0 | } |
755 | | |
756 | | /* ---------------- Main program ---------------- */ |
757 | | |
758 | | /* Write the definition of a TrueType font. */ |
759 | | static int |
760 | | compare_table_tags(const void *pt1, const void *pt2) |
761 | 841k | { |
762 | 841k | ulong t1 = u32(pt1), t2 = u32(pt2); |
763 | | |
764 | 841k | return (t1 < t2 ? -1 : t1 > t2 ? 1 : 0); |
765 | 841k | } |
766 | | static int |
767 | | psf_write_truetype_data(stream *s, gs_font_type42 *pfont, int options, |
768 | | psf_glyph_enum_t *penum, bool is_subset, |
769 | | const gs_const_string *alt_font_name) |
770 | 42.7k | { |
771 | 42.7k | gs_font *const font = (gs_font *)pfont; |
772 | 42.7k | gs_type42_data *d0 = &pfont->data; |
773 | 42.7k | gs_const_string font_name; |
774 | 42.7k | byte OffsetTable[12]; |
775 | 42.7k | uint numTables_stored, numTables, numTables_out; |
776 | 42.7k | byte tables[MAX_NUM_TT_TABLES * 16]; |
777 | 42.7k | uint i; |
778 | 42.7k | ulong offset; |
779 | 42.7k | gs_glyph glyph, glyph_prev; |
780 | 42.7k | ulong max_glyph; |
781 | 42.7k | uint glyf_length, loca_length; |
782 | 42.7k | ulong glyf_checksum = 0L; /****** NO CHECKSUM ******/ |
783 | 42.7k | ulong loca_checksum[2] = {0L,0L}; |
784 | 42.7k | ulong glyf_alignment = 0; |
785 | 42.7k | uint numGlyphs = 0; /* original value from maxp */ |
786 | 42.7k | byte head[56]; /* 0 mod 4 */ |
787 | 42.7k | gs_type42_mtx_t mtx[2]; |
788 | 42.7k | post_t post; |
789 | 42.7k | ulong head_checksum, file_checksum = 0; |
790 | 42.7k | int indexToLocFormat = 0; |
791 | 42.7k | bool |
792 | 42.7k | writing_cid = (options & WRITE_TRUETYPE_CID) != 0, |
793 | 42.7k | writing_stripped = (options & WRITE_TRUETYPE_STRIPPED) != 0, |
794 | 42.7k | generate_mtx = (options & WRITE_TRUETYPE_HVMTX) != 0, |
795 | 42.7k | no_generate = writing_cid | writing_stripped, |
796 | 42.7k | have_cmap = no_generate, |
797 | 42.7k | have_name = !(options & WRITE_TRUETYPE_NAME), |
798 | 42.7k | have_OS_2 = no_generate, |
799 | 42.7k | have_post = no_generate; |
800 | 42.7k | int have_hvhea[2]; |
801 | 42.7k | uint cmap_length = 0; |
802 | 42.7k | ulong OS_2_start = 0; |
803 | 42.7k | uint OS_2_length = OS_2_LENGTH1; |
804 | 42.7k | ulong maxp_start = 0; |
805 | 42.7k | struct { int glyf, loca, cmap, name, os_2, mtx[2], post, head; |
806 | 42.7k | } subtable_positions; |
807 | 42.7k | gs_offset_t start_position = stell(s); |
808 | 42.7k | int enlarged_numGlyphs = 0; |
809 | 42.7k | int code; |
810 | 42.7k | int TTCFontOffset = 0; |
811 | | |
812 | 42.7k | memset(&subtable_positions, 0, sizeof(subtable_positions)); |
813 | 42.7k | have_hvhea[0] = have_hvhea[1] = 0; |
814 | 42.7k | if (alt_font_name) |
815 | 5.09k | font_name = *alt_font_name; |
816 | 37.6k | else |
817 | 37.6k | font_name.data = font->font_name.chars, |
818 | 37.6k | font_name.size = font->font_name.size; |
819 | | |
820 | | /* |
821 | | * Count the number of tables, including the eventual glyf and loca |
822 | | * (which may not actually be present in the font), and copy the |
823 | | * table directory. |
824 | | */ |
825 | | |
826 | 42.7k | #define W(a,b,c,d)\ |
827 | 1.16M | ( ((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) |
828 | | |
829 | 42.7k | TTCFontOffset = d0->subfontOffset; |
830 | 42.7k | READ_SFNTS(pfont, TTCFontOffset, 12, OffsetTable); |
831 | 42.7k | numTables_stored = U16(OffsetTable + 4); |
832 | 574k | for (i = numTables = 0; i < numTables_stored; ++i) { |
833 | 531k | byte tab[16]; |
834 | 531k | byte data[54]; |
835 | 531k | ulong start; |
836 | 531k | uint length; |
837 | | |
838 | 531k | if (numTables == MAX_NUM_TT_TABLES) |
839 | 0 | return_error(gs_error_limitcheck); |
840 | 531k | READ_SFNTS(pfont, TTCFontOffset + 12 + i * 16, 16, tab); |
841 | 531k | start = u32(tab + 8); |
842 | 531k | length = u32(tab + 12); |
843 | | /* Copy the table data now (a rudiment of old code). */ |
844 | 531k | memcpy(&tables[numTables * 16], tab, 16); |
845 | 531k | switch (u32(tab)) { |
846 | 42.7k | case W('h','e','a','d'): |
847 | 42.7k | if (length < 54) |
848 | 0 | return_error(gs_error_invalidfont); |
849 | 42.7k | length = 54; /* bug 688409 fig2.eps has length=56. */ |
850 | 42.7k | READ_SFNTS(pfont, start, length, data); |
851 | 42.7k | memcpy(head, data, length); |
852 | 42.7k | continue; |
853 | 37.6k | case W('g','l','y','f'): /* synthesized */ |
854 | 37.6k | case W('g','l','y','x'): /* Adobe bogus */ |
855 | 75.1k | case W('l','o','c','a'): /* synthesized */ |
856 | 75.1k | case W('l','o','c','x'): /* Adobe bogus */ |
857 | 75.1k | case W('g','d','i','r'): /* Adobe marker */ |
858 | 75.1k | continue; |
859 | 41.0k | case W('c','m','a','p'): |
860 | 41.0k | if (options & (WRITE_TRUETYPE_CMAP | WRITE_TRUETYPE_CID)) |
861 | 5.20k | continue; |
862 | 35.8k | have_cmap = true; |
863 | 35.8k | break; |
864 | 42.4k | case W('m','a','x','p'): |
865 | 42.4k | READ_SFNTS(pfont, start, length, data); |
866 | 42.4k | numGlyphs = U16(data + 4); |
867 | 42.4k | maxp_start = start; |
868 | 42.4k | break; |
869 | 40.7k | case W('n','a','m','e'): |
870 | 40.7k | if (writing_cid) |
871 | 574 | continue; |
872 | 40.1k | have_name = true; |
873 | 40.1k | break; |
874 | 29.0k | case W('O','S','/','2'): |
875 | 29.0k | if (writing_cid) |
876 | 540 | continue; |
877 | 28.4k | have_OS_2 = true; |
878 | 28.4k | if (length > OS_2_LENGTH5) |
879 | 0 | return_error(gs_error_invalidfont); |
880 | 28.4k | OS_2_start = start; |
881 | 28.4k | OS_2_length = length; |
882 | 28.4k | continue; |
883 | 38.2k | case W('p','o','s','t'): |
884 | 38.2k | have_post = true; |
885 | 38.2k | break; |
886 | 42.7k | case W('h','h','e','a'): |
887 | 42.7k | have_hvhea[0] = 1; |
888 | 42.7k | break; |
889 | 0 | case W('v','h','e','a'): |
890 | 0 | have_hvhea[1] = 1; |
891 | 0 | break; |
892 | 42.5k | case W('h','m','t','x'): |
893 | 42.5k | case W('v','m','t','x'): |
894 | 42.5k | if (generate_mtx) |
895 | 5.08k | continue; |
896 | | /* falls through */ |
897 | 79.8k | case W('c','v','t',' '): |
898 | 122k | case W('f','p','g','m'): |
899 | 164k | case W('p','r','e','p'): |
900 | 164k | break; /* always copy these if present */ |
901 | 468 | case W('D','S','I','G'): |
902 | 516 | case W('E','B','D','T'): |
903 | 564 | case W('E','B','L','C'): |
904 | 564 | case W('E','B','S','C'): |
905 | 916 | case W('G','D','E','F'): |
906 | 1.10k | case W('G','P','O','S'): |
907 | 2.28k | case W('g','a','s','p'): |
908 | 3.26k | case W('k','e','r','n'): |
909 | 3.26k | continue; |
910 | 6.66k | default: |
911 | 6.66k | if (writing_cid) |
912 | 538 | continue; |
913 | 6.12k | break; |
914 | 531k | } |
915 | 370k | numTables++; |
916 | 370k | } |
917 | | |
918 | | /* |
919 | | * Enumerate the glyphs to get the size of glyf and loca, |
920 | | * and to compute the checksums for these tables. |
921 | | */ |
922 | | |
923 | | /****** NO CHECKSUMS YET ******/ |
924 | 42.7k | for (max_glyph = 0, glyf_length = 0; |
925 | 161k | (code = psf_enumerate_glyphs_next(penum, &glyph)) != 1; |
926 | 118k | ) { |
927 | 118k | uint glyph_index; |
928 | 118k | gs_glyph_data_t glyph_data; |
929 | | |
930 | 118k | if (glyph < GS_MIN_CID_GLYPH) |
931 | 0 | return_error(gs_error_invalidfont); |
932 | 118k | glyph_index = glyph & ~GS_GLYPH_TAG; |
933 | 118k | if_debug1m('L', s->memory, "[L]glyph_index %u\n", glyph_index); |
934 | 118k | glyph_data.memory = pfont->memory; |
935 | 118k | if ((code = pfont->data.get_outline(pfont, glyph_index, &glyph_data)) >= 0) { |
936 | | /* Since indexToLocFormat==0 assumes even glyph lengths, |
937 | | round it up here. If later we choose indexToLocFormat==1, |
938 | | subtract the glyf_alignment to compensate it. */ |
939 | 118k | uint l = (glyph_data.bits.size + 1) & ~1; |
940 | | |
941 | 118k | max_glyph = max(max_glyph, glyph_index); |
942 | 118k | glyf_length += l; |
943 | 118k | if (l != glyph_data.bits.size) |
944 | 73 | glyf_alignment++; |
945 | 118k | if_debug1m('L', s->memory, "[L] size %u\n", glyph_data.bits.size); |
946 | 118k | gs_glyph_data_free(&glyph_data, "psf_write_truetype_data"); |
947 | 118k | } |
948 | 118k | } |
949 | 42.7k | if (writing_stripped) { |
950 | 37.6k | glyf_length = 0; |
951 | 37.6k | loca_length = 0; |
952 | 37.6k | } else { |
953 | 5.09k | if (max_glyph + 1 > numGlyphs) { |
954 | | /* Either original font is wrong, |
955 | | or we added glyphs to it due to font merge. |
956 | | Need to adjust maxp, hmtx, vmtx, vdmx, hdmx, |
957 | | assuming that the merge doesn't change hhea |
958 | | and other tables. |
959 | | Since changing hdmx, vdmx is too difficult, |
960 | | and since they're not required for PDF, |
961 | | we'll simply skip them. |
962 | | */ |
963 | 0 | enlarged_numGlyphs = max_glyph + 1; |
964 | 0 | if (enlarged_numGlyphs > 0xFFFF) { |
965 | 0 | emprintf1(pfont->memory, |
966 | 0 | "The number of glyphs %d exceeds capability of True Type format.\n", |
967 | 0 | enlarged_numGlyphs); |
968 | 0 | return_error(gs_error_unregistered); |
969 | 0 | } |
970 | 0 | loca_length = (enlarged_numGlyphs + 1) << 2; |
971 | 0 | remove_table(tables, (char *)"hdmx", &numTables); |
972 | 0 | remove_table(tables, (char *)"vdmx", &numTables); |
973 | 0 | } else |
974 | 5.09k | loca_length = (numGlyphs + 1) << 2; |
975 | 5.09k | indexToLocFormat = (glyf_length > 0x1fffc); |
976 | 5.09k | if (!indexToLocFormat) |
977 | 5.09k | loca_length >>= 1; |
978 | 0 | else |
979 | 0 | glyf_length -= glyf_alignment; |
980 | | /* Acrobat Reader won't accept fonts with empty glyfs. */ |
981 | 5.09k | if (glyf_length == 0) |
982 | 496 | glyf_length = 1; |
983 | 5.09k | } |
984 | 42.7k | if_debug2m('l', s->memory, "[l]max_glyph = %lu, glyf_length = %lu\n", |
985 | 42.7k | (ulong)max_glyph, (ulong)glyf_length); |
986 | | |
987 | | /* |
988 | | * If necessary, compute the length of the post table. Note that we |
989 | | * only generate post entries for characters in the Encoding. */ |
990 | | |
991 | 42.7k | if (!have_post) { |
992 | 1.12k | memset(&post, 0, sizeof(post)); |
993 | 1.12k | if (options & WRITE_TRUETYPE_POST) { |
994 | 0 | code = compute_post(font, &post); |
995 | 0 | if (code < 0) |
996 | 0 | return code; |
997 | 0 | } else |
998 | 1.12k | post.length = 32; /* dummy table */ |
999 | 1.12k | } |
1000 | | |
1001 | | /* Fix up the head table. */ |
1002 | | |
1003 | 42.7k | memset(head + 8, 0, 4); |
1004 | 42.7k | head[50] = 0x00; |
1005 | 42.7k | head[51] = (byte)indexToLocFormat; |
1006 | 42.7k | memset(head + 54, 0, 2); |
1007 | 641k | for (head_checksum = 0, i = 0; i < 56; i += 4) |
1008 | 598k | head_checksum += u32(&head[i]); |
1009 | | |
1010 | | /* |
1011 | | * Construct the table directory, except for glyf, loca, head, OS/2, |
1012 | | * and, if necessary, generated cmap, name, and post tables. |
1013 | | * Note that the existing directory is already sorted by tag. |
1014 | | */ |
1015 | | |
1016 | 42.7k | numTables_out = numTables + 1 /* head */ |
1017 | 42.7k | + !writing_stripped * 2 /* glyf, loca */ |
1018 | 42.7k | + generate_mtx * (have_hvhea[0] + have_hvhea[1]) /* hmtx, vmtx */ |
1019 | 42.7k | + !have_OS_2 /* OS/2 */ |
1020 | 42.7k | + !have_cmap + !have_name + !have_post; |
1021 | 42.7k | if (numTables_out >= MAX_NUM_TT_TABLES) |
1022 | 0 | return_error(gs_error_limitcheck); |
1023 | 42.7k | offset = 12 + numTables_out * 16; |
1024 | 412k | for (i = 0; i < numTables; ++i) { |
1025 | 369k | byte *tab = &tables[i * 16]; |
1026 | 369k | ulong length = u32(tab + 12); |
1027 | | |
1028 | 369k | offset += round_up(length, 4); |
1029 | 369k | } |
1030 | | |
1031 | | /* Make the table directory entries for generated tables. */ |
1032 | | |
1033 | 42.7k | { |
1034 | 42.7k | byte *tab = &tables[numTables * 16]; |
1035 | | |
1036 | 42.7k | if (!writing_stripped) { |
1037 | 5.09k | subtable_positions.glyf = offset; |
1038 | 5.09k | offset = put_table(tab, "glyf", glyf_checksum, |
1039 | 5.09k | offset, glyf_length); |
1040 | 5.09k | tab += 16; |
1041 | 5.09k | subtable_positions.loca = offset; |
1042 | 5.09k | offset = put_table(tab, "loca", loca_checksum[indexToLocFormat], |
1043 | 5.09k | offset, loca_length); |
1044 | 5.09k | tab += 16; |
1045 | 5.09k | } |
1046 | | |
1047 | 42.7k | if (!have_cmap) { |
1048 | 4.79k | cmap_length = size_cmap(font, TT_BIAS, 256, |
1049 | 4.79k | GS_MIN_GLYPH_INDEX + max_glyph, options); |
1050 | 4.79k | subtable_positions.cmap = offset; |
1051 | 4.79k | offset = put_table(tab, "cmap", 0L /****** NO CHECKSUM ******/, |
1052 | 4.79k | offset, cmap_length); |
1053 | 4.79k | tab += 16; |
1054 | 4.79k | } |
1055 | | |
1056 | 42.7k | if (!have_name) { |
1057 | 108 | subtable_positions.name = offset; |
1058 | 108 | offset = put_table(tab, "name", 0L /****** NO CHECKSUM ******/, |
1059 | 108 | offset, size_name(&font_name)); |
1060 | 108 | tab += 16; |
1061 | 108 | } |
1062 | | |
1063 | 42.7k | if (!no_generate) { |
1064 | 4.79k | subtable_positions.os_2 = offset; |
1065 | 4.79k | offset = put_table(tab, "OS/2", 0L /****** NO CHECKSUM ******/, |
1066 | 4.79k | offset, OS_2_length); |
1067 | 4.79k | tab += 16; |
1068 | 4.79k | } |
1069 | | |
1070 | 42.7k | if (generate_mtx) |
1071 | 15.2k | for (i = 0; i < 2; ++i) |
1072 | 10.1k | if (have_hvhea[i]) { |
1073 | 5.09k | subtable_positions.mtx[i] = offset; |
1074 | 5.09k | offset = put_table(tab, (i ? "vmtx" : "hmtx"), |
1075 | 5.09k | 0L /****** NO CHECKSUM ******/, |
1076 | 5.09k | offset, |
1077 | 5.09k | size_mtx(pfont, &mtx[i], max_glyph, numGlyphs, i)); |
1078 | 5.09k | tab += 16; |
1079 | 5.09k | } |
1080 | | |
1081 | 42.7k | if (!have_post) { |
1082 | 1.12k | subtable_positions.post = offset; |
1083 | 1.12k | offset = put_table(tab, "post", 0L /****** NO CHECKSUM ******/, |
1084 | 1.12k | offset, post.length); |
1085 | 1.12k | tab += 16; |
1086 | 1.12k | } |
1087 | | |
1088 | | /* |
1089 | | * Note that the 'head' table must have length 54, even though |
1090 | | * it occupies 56 bytes on the file. |
1091 | | */ |
1092 | 42.7k | subtable_positions.head = offset; |
1093 | 42.7k | (void)put_table(tab, "head", head_checksum, offset, 54); |
1094 | 42.7k | } |
1095 | 42.7k | numTables = numTables_out; |
1096 | | |
1097 | | /* Write the font header. */ |
1098 | | |
1099 | 42.7k | { |
1100 | 42.7k | static const byte version[4] = {0, 1, 0, 0}; |
1101 | | |
1102 | 42.7k | stream_write(s, version, 4); |
1103 | 42.7k | } |
1104 | 42.7k | put_ushort(s, numTables); |
1105 | 213k | for (i = 0; 1 << i <= numTables; ++i) |
1106 | 171k | DO_NOTHING; |
1107 | 42.7k | --i; |
1108 | 42.7k | put_ushort(s, 16 << i); /* searchRange */ |
1109 | 42.7k | put_ushort(s, i); /* entrySelectors */ |
1110 | 42.7k | put_ushort(s, numTables * 16 - (16 << i)); /* rangeShift */ |
1111 | | |
1112 | | /* Write the table directory. */ |
1113 | | |
1114 | 42.7k | qsort(tables, numTables, 16, compare_table_tags); |
1115 | 42.7k | offset = 12 + numTables * 16; |
1116 | 481k | for (i = 0; i < numTables; ++i) { |
1117 | 438k | const byte *tab = &tables[i * 16]; |
1118 | 438k | byte entry[16]; |
1119 | | |
1120 | 438k | memcpy(entry, tab, 16); |
1121 | 438k | if (entry[8] < 0x40) { |
1122 | | /* Not a generated table. */ |
1123 | 368k | uint length = u32(tab + 12); |
1124 | | |
1125 | 368k | put_u32(entry + 8, offset); |
1126 | 368k | offset += round_up(length, 4); |
1127 | 368k | } else { |
1128 | 70.0k | entry[8] -= 0x40; |
1129 | 70.0k | } |
1130 | 438k | stream_write(s, entry, 16); |
1131 | 438k | } |
1132 | | |
1133 | | /* Write tables other than the ones we generate here. */ |
1134 | | |
1135 | 481k | for (i = 0; i < numTables; ++i) { |
1136 | 438k | const byte *tab = &tables[i * 16]; |
1137 | | |
1138 | 438k | if (tab[8] < 0x40) { |
1139 | 368k | ulong start = u32(tab + 8); |
1140 | 368k | uint length = u32(tab + 12); |
1141 | | |
1142 | 368k | switch (u32(tab)) { |
1143 | 0 | case W('O','S','/','2'): |
1144 | 0 | if (!have_cmap) { |
1145 | | /* |
1146 | | * Adjust the first and last character indices in the OS/2 |
1147 | | * table to reflect the values in the generated cmap. |
1148 | | */ |
1149 | 0 | byte pos2[OS_2_LENGTH5]; |
1150 | 0 | ttf_OS_2_t os2; |
1151 | |
|
1152 | 0 | READ_SFNTS(pfont, OS_2_start, OS_2_length, pos2); |
1153 | 0 | memcpy(&os2, pos2, min(OS_2_length, sizeof(os2))); |
1154 | 0 | update_OS_2(&os2, TT_BIAS, 256); |
1155 | 0 | stream_write(s, &os2, OS_2_length); |
1156 | 0 | put_pad(s, OS_2_length); |
1157 | 0 | } else { |
1158 | | /* Just copy the existing OS/2 table. */ |
1159 | 0 | write_range(s, pfont, OS_2_start, OS_2_length); |
1160 | 0 | put_pad(s, OS_2_length); |
1161 | 0 | } |
1162 | 0 | break; |
1163 | 42.4k | case W('m','a','x','p'): |
1164 | 42.4k | if (enlarged_numGlyphs) { |
1165 | | /* Must keep the table size. */ |
1166 | 0 | byte buf[6]; |
1167 | |
|
1168 | 0 | READ_SFNTS(pfont, maxp_start, sizeof(buf), buf); |
1169 | 0 | put_u16(buf + 4, enlarged_numGlyphs); |
1170 | 0 | stream_write(s, buf, min(length, sizeof(buf))); |
1171 | 0 | if (length > sizeof(buf)) /* Paranoid Safety */ |
1172 | 0 | write_range(s, pfont, start + sizeof(buf), length - sizeof(buf)); |
1173 | 0 | } else |
1174 | 42.4k | write_range(s, pfont, start, length); |
1175 | 42.4k | break; |
1176 | 42.7k | case W('h','h','e','a'): |
1177 | 42.7k | case W('v','h','e','a'): |
1178 | 42.7k | if (generate_mtx) { |
1179 | 5.09k | write_range(s, pfont, start, length - 2); /* 34 */ |
1180 | 5.09k | put_ushort(s, mtx[tab[0] == 'v'].numMetrics); |
1181 | 5.09k | break; |
1182 | 5.09k | } |
1183 | | /* falls through */ |
1184 | 321k | default: |
1185 | 321k | write_range(s, pfont, start, length); |
1186 | 368k | } |
1187 | 368k | put_pad(s, length); |
1188 | 368k | } |
1189 | 438k | } |
1190 | | |
1191 | 42.7k | if (!writing_stripped) { |
1192 | 5.09k | int n = max(numGlyphs, enlarged_numGlyphs) + 1; |
1193 | | |
1194 | | /* Write glyf. */ |
1195 | | |
1196 | 5.09k | if (check_position(pfont->memory, |
1197 | 5.09k | subtable_positions.glyf + start_position, |
1198 | 5.09k | stell(s))) |
1199 | 0 | return_error(gs_error_unregistered); |
1200 | 5.09k | psf_enumerate_glyphs_reset(penum); |
1201 | 123k | for (offset = 0; psf_enumerate_glyphs_next(penum, &glyph) != 1; ) { |
1202 | 118k | gs_glyph_data_t glyph_data; |
1203 | | |
1204 | 118k | glyph_data.memory = pfont->memory; |
1205 | 118k | if ((code = pfont->data.get_outline(pfont, |
1206 | 118k | glyph & ~GS_GLYPH_TAG, |
1207 | 118k | &glyph_data)) >= 0 |
1208 | 118k | ) { |
1209 | 118k | uint l = glyph_data.bits.size, zero = 0; |
1210 | | |
1211 | 118k | if (!indexToLocFormat) |
1212 | 118k | l = (l + 1) & ~1; |
1213 | 118k | stream_write(s, glyph_data.bits.data, glyph_data.bits.size); |
1214 | 118k | if (glyph_data.bits.size < l) |
1215 | 73 | stream_write(s, &zero, 1); |
1216 | 118k | offset += l; |
1217 | 118k | if_debug2m('L', s->memory, "[L]glyf index = %u, size = %u\n", |
1218 | 118k | i, glyph_data.bits.size); |
1219 | 118k | gs_glyph_data_free(&glyph_data, "psf_write_truetype_data"); |
1220 | 118k | } |
1221 | 118k | } |
1222 | 5.09k | if_debug1m('l', s->memory, "[l]glyf final offset = %lu\n", offset); |
1223 | | /* Add a dummy byte if necessary to make glyf non-empty. */ |
1224 | 5.59k | while (offset < glyf_length) |
1225 | 496 | stream_putc(s, 0), ++offset; |
1226 | 5.09k | put_pad(s, (uint)offset); |
1227 | | |
1228 | | /* Write loca. */ |
1229 | | |
1230 | 5.09k | if (check_position(pfont->memory, |
1231 | 5.09k | subtable_positions.loca + start_position, |
1232 | 5.09k | stell(s))) |
1233 | 0 | return_error(gs_error_unregistered); |
1234 | 5.09k | psf_enumerate_glyphs_reset(penum); |
1235 | 5.09k | glyph_prev = 0; |
1236 | 123k | for (offset = 0; psf_enumerate_glyphs_next(penum, &glyph) != 1; ) { |
1237 | 118k | gs_glyph_data_t glyph_data; |
1238 | 118k | uint glyph_index = glyph & ~GS_GLYPH_TAG; |
1239 | | |
1240 | 3.81M | for (; glyph_prev <= glyph_index; ++glyph_prev) |
1241 | 3.69M | put_loca(s, offset, indexToLocFormat); |
1242 | 118k | glyph_data.memory = pfont->memory; |
1243 | 118k | if ((code = pfont->data.get_outline(pfont, glyph_index, |
1244 | 118k | &glyph_data)) >= 0 |
1245 | 118k | ) { |
1246 | 118k | uint l = glyph_data.bits.size; |
1247 | | |
1248 | 118k | if (!indexToLocFormat) |
1249 | 118k | l = (l + 1) & ~1; |
1250 | 118k | offset += l; |
1251 | 118k | gs_glyph_data_free(&glyph_data, "psf_write_truetype_data"); |
1252 | 118k | } |
1253 | | |
1254 | 118k | } |
1255 | | /* Pad to numGlyphs + 1 entries (including the trailing entry). */ |
1256 | 16.8M | for (; glyph_prev < n; ++glyph_prev) |
1257 | 16.8M | put_loca(s, offset, indexToLocFormat); |
1258 | 5.09k | put_pad(s, loca_length); |
1259 | | |
1260 | | /* If necessary, write cmap, name, and OS/2. */ |
1261 | | |
1262 | 5.09k | if (!have_cmap) { |
1263 | 4.79k | if (check_position(pfont->memory, |
1264 | 4.79k | subtable_positions.cmap + start_position, |
1265 | 4.79k | stell(s))) |
1266 | 0 | return_error(gs_error_unregistered); |
1267 | 4.79k | write_cmap(s, font, TT_BIAS, 256, GS_MIN_GLYPH_INDEX + max_glyph, |
1268 | 4.79k | options, cmap_length); |
1269 | 4.79k | } |
1270 | 5.09k | if (!have_name) { |
1271 | 108 | if (check_position(pfont->memory, |
1272 | 108 | subtable_positions.name + start_position, |
1273 | 108 | stell(s))) |
1274 | 0 | return_error(gs_error_unregistered); |
1275 | 108 | write_name(s, &font_name); |
1276 | 108 | } |
1277 | 5.09k | if (!have_OS_2) { |
1278 | 4.79k | if (check_position(pfont->memory, |
1279 | 4.79k | subtable_positions.os_2 + start_position, |
1280 | 4.79k | stell(s))) |
1281 | 0 | return_error(gs_error_unregistered); |
1282 | 4.79k | write_OS_2(s, font, TT_BIAS, 256); |
1283 | 4.79k | } |
1284 | | |
1285 | | /* If necessary, write [hv]mtx. */ |
1286 | | |
1287 | 5.09k | if (generate_mtx) |
1288 | 15.2k | for (i = 0; i < 2; ++i) |
1289 | 10.1k | if (have_hvhea[i]) { |
1290 | 5.09k | if (check_position(pfont->memory, |
1291 | 5.09k | subtable_positions.mtx[i] + start_position, |
1292 | 5.09k | stell(s))) |
1293 | 0 | return_error(gs_error_unregistered); |
1294 | 5.09k | write_mtx(s, pfont, &mtx[i], i); |
1295 | 5.09k | put_pad(s, mtx[i].length); |
1296 | 5.09k | } |
1297 | | |
1298 | | /* If necessary, write post. */ |
1299 | | |
1300 | 5.09k | if (!have_post) { |
1301 | 1.12k | if (check_position(pfont->memory, |
1302 | 1.12k | subtable_positions.post + start_position, |
1303 | 1.12k | stell(s))) |
1304 | 0 | return_error(gs_error_unregistered); |
1305 | 1.12k | if (options & WRITE_TRUETYPE_POST) { |
1306 | 0 | code = write_post(s, font, &post); |
1307 | 0 | if (code < 0) |
1308 | 0 | return code; |
1309 | 1.12k | } else { |
1310 | 1.12k | byte post_initial[32 + 2]; |
1311 | | |
1312 | 1.12k | memset(post_initial, 0, 32); |
1313 | 1.12k | put_u32(post_initial, 0x00030000); |
1314 | 1.12k | stream_write(s, post_initial, 32); |
1315 | 1.12k | } |
1316 | 1.12k | } |
1317 | 5.09k | } |
1318 | | |
1319 | | /* Write head. */ |
1320 | | |
1321 | | /****** CHECKSUM WAS NEVER COMPUTED ******/ |
1322 | | /* |
1323 | | * The following nonsense is to avoid warnings about the constant |
1324 | | * 0xb1b0afbaL being "unsigned in ANSI C, signed with -traditional". |
1325 | | */ |
1326 | 42.7k | #if ARCH_SIZEOF_LONG > ARCH_SIZEOF_INT |
1327 | 42.7k | # define HEAD_MAGIC 0xb1b0afbaL |
1328 | | #else |
1329 | | # define HEAD_MAGIC ((ulong)~0x4e4f5045) |
1330 | | #endif |
1331 | 42.7k | put_u32(head + 8, HEAD_MAGIC - file_checksum); /* per spec */ |
1332 | 42.7k | #undef HEAD_MAGIC |
1333 | 42.7k | if (check_position(pfont->memory, |
1334 | 42.7k | subtable_positions.head + start_position, |
1335 | 42.7k | stell(s))) |
1336 | 9.09k | return_error(gs_error_unregistered); |
1337 | 33.6k | stream_write(s, head, 56); |
1338 | | |
1339 | 33.6k | return 0; |
1340 | 42.7k | } |
1341 | | |
1342 | | /* Write a TrueType font. */ |
1343 | | int |
1344 | | psf_write_truetype_font(stream *s, gs_font_type42 *pfont, int options, |
1345 | | gs_glyph *orig_subset_glyphs, uint orig_subset_size, |
1346 | | const gs_const_string *alt_font_name) |
1347 | 4.79k | { |
1348 | 4.79k | gs_font *const font = (gs_font *)pfont; |
1349 | 4.79k | psf_glyph_enum_t genum; |
1350 | 4.79k | gs_glyph subset_data[256 * MAX_COMPOSITE_PIECES]; |
1351 | 4.79k | gs_glyph *subset_glyphs = orig_subset_glyphs; |
1352 | 4.79k | uint subset_size = orig_subset_size; |
1353 | | |
1354 | | /* Sort the subset glyphs, if any. */ |
1355 | | |
1356 | 4.79k | if (subset_glyphs) { |
1357 | | /* Add the component glyphs for composites. */ |
1358 | 0 | int code; |
1359 | |
|
1360 | 0 | memcpy(subset_data, orig_subset_glyphs, |
1361 | 0 | sizeof(gs_glyph) * subset_size); |
1362 | 0 | subset_glyphs = subset_data; |
1363 | 0 | code = psf_add_subset_pieces(subset_glyphs, &subset_size, |
1364 | 0 | countof(subset_data), |
1365 | 0 | countof(subset_data), |
1366 | 0 | font); |
1367 | 0 | if (code < 0) |
1368 | 0 | return code; |
1369 | 0 | subset_size = psf_sort_glyphs(subset_glyphs, subset_size); |
1370 | 0 | } |
1371 | 4.79k | psf_enumerate_glyphs_begin(&genum, font, subset_glyphs, |
1372 | 4.79k | (subset_glyphs ? subset_size : 0), |
1373 | 4.79k | GLYPH_SPACE_INDEX); |
1374 | 4.79k | return psf_write_truetype_data(s, pfont, options & ~WRITE_TRUETYPE_CID, |
1375 | 4.79k | &genum, subset_glyphs != 0, alt_font_name); |
1376 | 4.79k | } |
1377 | | /* Write a stripped TrueType font. */ |
1378 | | int |
1379 | | psf_write_truetype_stripped(stream *s, gs_font_type42 *pfont) |
1380 | 37.0k | { |
1381 | 37.0k | psf_glyph_enum_t genum; |
1382 | 37.0k | byte no_subset = 0; |
1383 | | |
1384 | 37.0k | psf_enumerate_bits_begin(&genum, (gs_font *)pfont, &no_subset, 0, |
1385 | 37.0k | GLYPH_SPACE_INDEX); |
1386 | 37.0k | return psf_write_truetype_data(s, pfont, WRITE_TRUETYPE_STRIPPED, |
1387 | 37.0k | &genum, true, NULL); |
1388 | 37.0k | } |
1389 | | |
1390 | | /* Write a CIDFontType 2 font. */ |
1391 | | int |
1392 | | psf_write_cid2_font(stream *s, gs_font_cid2 *pfont, int options, |
1393 | | const byte *subset_bits, uint subset_size, |
1394 | | const gs_const_string *alt_font_name) |
1395 | 298 | { |
1396 | 298 | gs_font *const font = (gs_font *)pfont; |
1397 | 298 | psf_glyph_enum_t genum; |
1398 | | |
1399 | 298 | psf_enumerate_bits_begin(&genum, font, subset_bits, |
1400 | 298 | (subset_bits ? subset_size : 0), |
1401 | 298 | GLYPH_SPACE_INDEX); |
1402 | 298 | return psf_write_truetype_data(s, (gs_font_type42 *)font, |
1403 | 298 | options | WRITE_TRUETYPE_CID, &genum, |
1404 | 298 | subset_bits != 0, alt_font_name); |
1405 | 298 | } |
1406 | | |
1407 | | /* Write a stripped CIDFontType 2 font. */ |
1408 | | int |
1409 | | psf_write_cid2_stripped(stream *s, gs_font_cid2 *pfont) |
1410 | 649 | { |
1411 | 649 | gs_font *const font = (gs_font *)pfont; |
1412 | 649 | psf_glyph_enum_t genum; |
1413 | 649 | byte no_subset = 0; |
1414 | | |
1415 | 649 | psf_enumerate_bits_begin(&genum, font, &no_subset, 0, |
1416 | 649 | GLYPH_SPACE_INDEX); |
1417 | 649 | return psf_write_truetype_data(s, (gs_font_type42 *)font, |
1418 | 649 | WRITE_TRUETYPE_STRIPPED | |
1419 | 649 | WRITE_TRUETYPE_CID, |
1420 | 649 | &genum, true, NULL); |
1421 | 649 | } |