/src/ghostpdl/pcl/pl/plfont.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 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 | | /* plfont.c */ |
18 | | /* PCL font handling library -- operations on entire fonts */ |
19 | | #include "memory_.h" |
20 | | #include "stdio_.h" |
21 | | #include "gdebug.h" |
22 | | #include "gp.h" |
23 | | #include "gserrors.h" |
24 | | #include "gstypes.h" |
25 | | #include "gsmemory.h" |
26 | | #include "gsstruct.h" |
27 | | #include "gsmatrix.h" |
28 | | #include "gsstate.h" |
29 | | #include "gschar.h" |
30 | | #include "gsimage.h" |
31 | | #include "gsutil.h" |
32 | | #include "gxfcache.h" |
33 | | #include "gxfont.h" |
34 | | #include "gxfont42.h" |
35 | | #include "gzstate.h" |
36 | | #include "plfont.h" |
37 | | #include "plvalue.h" |
38 | | #include "plchar.h" |
39 | | #include "strmio.h" |
40 | | #include "stream.h" |
41 | | |
42 | | #include "plfapi.h" |
43 | | |
44 | | /* Structure descriptors */ |
45 | | private_st_pl_font(); |
46 | | |
47 | | /* Define accessors for unaligned, big-endian quantities. */ |
48 | 32.5k | #define u16(bptr) pl_get_uint16(bptr) |
49 | | #define s16(bptr) pl_get_int16(bptr) |
50 | | /**** ASSUME uint >= 32 BITS ****/ |
51 | 32.4k | #define u32(bptr) (uint)pl_get_uint32(bptr) |
52 | | |
53 | | /* ---------------- Utilities ---------------- */ |
54 | | /* Free a font. This is the freeing procedure in the font dictionary. */ |
55 | | void |
56 | | pl_free_font(gs_memory_t * mem, void *plf, client_name_t cname) |
57 | 1.97M | { |
58 | 1.97M | pl_font_t *plfont = plf; |
59 | | |
60 | | /* Free the characters. */ |
61 | 1.97M | if (!plfont->data_are_permanent) { |
62 | 1.95M | if (plfont->glyphs.table) { |
63 | 358 | uint i; |
64 | | |
65 | 105k | for (i = plfont->glyphs.size; i > 0;) { |
66 | 105k | void *data = (void *)plfont->glyphs.table[--i].data; |
67 | | |
68 | 105k | if (data) |
69 | 1.71k | gs_free_object(mem, data, cname); |
70 | 105k | } |
71 | 358 | } |
72 | 1.95M | gs_free_object(mem, (void *)plfont->header, cname); |
73 | 1.95M | plfont->header = 0; /* see hack note above */ |
74 | 1.95M | } |
75 | | |
76 | | /* free any nodes in the widths cache */ |
77 | 1.97M | pl_font_glyph_width_cache_remove_nodes(plfont); |
78 | | |
79 | | /* Free the font data itself. */ |
80 | 1.97M | gs_free_object(mem, (void *)plfont->char_glyphs.table, cname); |
81 | 1.97M | gs_free_object(mem, (void *)plfont->glyphs.table, cname); |
82 | 1.97M | if (plfont->pfont) { /* might be only partially constructed */ |
83 | 1.97M | gs_purge_font_from_char_caches_completely(plfont->pfont); |
84 | 1.97M | (void)gs_purge_font(plfont->pfont); |
85 | 1.97M | gs_free_object(mem, plfont->pfont, cname); |
86 | 1.97M | } |
87 | 1.97M | if (plfont->font_file) { |
88 | 1.64M | gs_free_object(mem, plfont->font_file, cname); |
89 | 1.64M | plfont->font_file = 0; |
90 | 1.64M | } |
91 | 1.97M | if (plfont->names != NULL) { |
92 | 0 | int i = 0; |
93 | 0 | for (i = 0;i < plfont->next_name_index; i++) |
94 | 0 | gs_free_object(mem, plfont->names[i], "freeing names table"); |
95 | 0 | gs_free_object(mem, plfont->names, "free names table"); |
96 | 0 | plfont->names = NULL; |
97 | 0 | plfont->max_name_index = plfont->next_name_index = 0; |
98 | 0 | } |
99 | 1.97M | gs_free_object(mem, plf, cname); |
100 | 1.97M | } |
101 | | |
102 | | /* ---------------- Library callbacks ---------------- */ |
103 | | |
104 | | const char *pl_mac_names[258] = { |
105 | | ".notdef", |
106 | | ".null", |
107 | | "nonmarkingreturn", |
108 | | "space", |
109 | | "exclam", |
110 | | "quotedbl", |
111 | | "numbersign", |
112 | | "dollar", |
113 | | "percent", |
114 | | "ampersand", |
115 | | "quotesingle", |
116 | | "parenleft", |
117 | | "parenright", |
118 | | "asterisk", |
119 | | "plus", |
120 | | "comma", |
121 | | "hyphen", |
122 | | "period", |
123 | | "slash", |
124 | | "zero", |
125 | | "one", |
126 | | "two", |
127 | | "three", |
128 | | "four", |
129 | | "five", |
130 | | "six", |
131 | | "seven", |
132 | | "eight", |
133 | | "nine", |
134 | | "colon", |
135 | | "semicolon", |
136 | | "less", |
137 | | "equal", |
138 | | "greater", |
139 | | "question", |
140 | | "at", |
141 | | "A", |
142 | | "B", |
143 | | "C", |
144 | | "D", |
145 | | "E", |
146 | | "F", |
147 | | "G", |
148 | | "H", |
149 | | "I", |
150 | | "J", |
151 | | "K", |
152 | | "L", |
153 | | "M", |
154 | | "N", |
155 | | "O", |
156 | | "P", |
157 | | "Q", |
158 | | "R", |
159 | | "S", |
160 | | "T", |
161 | | "U", |
162 | | "V", |
163 | | "W", |
164 | | "X", |
165 | | "Y", |
166 | | "Z", |
167 | | "bracketleft", |
168 | | "backslash", |
169 | | "bracketright", |
170 | | "asciicircum", |
171 | | "underscore", |
172 | | "grave", |
173 | | "a", |
174 | | "b", |
175 | | "c", |
176 | | "d", |
177 | | "e", |
178 | | "f", |
179 | | "g", |
180 | | "h", |
181 | | "i", |
182 | | "j", |
183 | | "k", |
184 | | "l", |
185 | | "m", |
186 | | "n", |
187 | | "o", |
188 | | "p", |
189 | | "q", |
190 | | "r", |
191 | | "s", |
192 | | "t", |
193 | | "u", |
194 | | "v", |
195 | | "w", |
196 | | "x", |
197 | | "y", |
198 | | "z", |
199 | | "braceleft", |
200 | | "bar", |
201 | | "braceright", |
202 | | "asciitilde", |
203 | | "Adieresis", |
204 | | "Aring", |
205 | | "Ccedilla", |
206 | | "Eacute", |
207 | | "Ntilde", |
208 | | "Odieresis", |
209 | | "Udieresis", |
210 | | "aacute", |
211 | | "agrave", |
212 | | "acircumflex", |
213 | | "adieresis", |
214 | | "atilde", |
215 | | "aring", |
216 | | "ccedilla", |
217 | | "eacute", |
218 | | "egrave", |
219 | | "ecircumflex", |
220 | | "edieresis", |
221 | | "iacute", |
222 | | "igrave", |
223 | | "icircumflex", |
224 | | "idieresis", |
225 | | "ntilde", |
226 | | "oacute", |
227 | | "ograve", |
228 | | "ocircumflex", |
229 | | "odieresis", |
230 | | "otilde", |
231 | | "uacute", |
232 | | "ugrave", |
233 | | "ucircumflex", |
234 | | "udieresis", |
235 | | "dagger", |
236 | | "degree", |
237 | | "cent", |
238 | | "sterling", |
239 | | "section", |
240 | | "bullet", |
241 | | "paragraph", |
242 | | "germandbls", |
243 | | "registered", |
244 | | "copyright", |
245 | | "trademark", |
246 | | "acute", |
247 | | "dieresis", |
248 | | "notequal", |
249 | | "AE", |
250 | | "Oslash", |
251 | | "infinity", |
252 | | "plusminus", |
253 | | "lessequal", |
254 | | "greaterequal", |
255 | | "yen", |
256 | | "mu", |
257 | | "partialdiff", |
258 | | "summation", |
259 | | "product", |
260 | | "pi", |
261 | | "integral", |
262 | | "ordfeminine", |
263 | | "ordmasculine", |
264 | | "Omega", |
265 | | "ae", |
266 | | "oslash", |
267 | | "questiondown", |
268 | | "exclamdown", |
269 | | "logicalnot", |
270 | | "radical", |
271 | | "florin", |
272 | | "approxequal", |
273 | | "Delta", |
274 | | "guillemotleft", |
275 | | "guillemotright", |
276 | | "ellipsis", |
277 | | "nonbreakingspace", |
278 | | "Agrave", |
279 | | "Atilde", |
280 | | "Otilde", |
281 | | "OE", |
282 | | "oe", |
283 | | "endash", |
284 | | "emdash", |
285 | | "quotedblleft", |
286 | | "quotedblright", |
287 | | "quoteleft", |
288 | | "quoteright", |
289 | | "divide", |
290 | | "lozenge", |
291 | | "ydieresis", |
292 | | "Ydieresis", |
293 | | "fraction", |
294 | | "currency", |
295 | | "guilsinglleft", |
296 | | "guilsinglright", |
297 | | "fi", |
298 | | "fl", |
299 | | "daggerdbl", |
300 | | "periodcentered", |
301 | | "quotesinglbase", |
302 | | "quotedblbase", |
303 | | "perthousand", |
304 | | "Acircumflex", |
305 | | "Ecircumflex", |
306 | | "Aacute", |
307 | | "Edieresis", |
308 | | "Egrave", |
309 | | "Iacute", |
310 | | "Icircumflex", |
311 | | "Idieresis", |
312 | | "Igrave", |
313 | | "Oacute", |
314 | | "Ocircumflex", |
315 | | "apple", |
316 | | "Ograve", |
317 | | "Uacute", |
318 | | "Ucircumflex", |
319 | | "Ugrave", |
320 | | "dotlessi", |
321 | | "circumflex", |
322 | | "tilde", |
323 | | "macron", |
324 | | "breve", |
325 | | "dotaccent", |
326 | | "ring", |
327 | | "cedilla", |
328 | | "hungarumlaut", |
329 | | "ogonek", |
330 | | "caron", |
331 | | "Lslash", |
332 | | "lslash", |
333 | | "Scaron", |
334 | | "scaron", |
335 | | "Zcaron", |
336 | | "zcaron", |
337 | | "brokenbar", |
338 | | "Eth", |
339 | | "eth", |
340 | | "Yacute", |
341 | | "yacute", |
342 | | "Thorn", |
343 | | "thorn", |
344 | | "minus", |
345 | | "multiply", |
346 | | "onesuperior", |
347 | | "twosuperior", |
348 | | "threesuperior", |
349 | | "onehalf", |
350 | | "onequarter", |
351 | | "threequarters", |
352 | | "franc", |
353 | | "Gbreve", |
354 | | "gbreve", |
355 | | "Idotaccent", |
356 | | "Scedilla", |
357 | | "scedilla", |
358 | | "Cacute", |
359 | | "cacute", |
360 | | "Ccaron", |
361 | | "ccaron", |
362 | | "dcroat" |
363 | | }; |
364 | | |
365 | | static int |
366 | | pl_glyph_name(gs_font * pfont, gs_glyph glyph, gs_const_string * pstr) |
367 | 0 | { |
368 | 0 | uint table_length; |
369 | 0 | ulong table_offset; |
370 | 0 | pl_font_t * plfont = (pl_font_t *)pfont->client_data; |
371 | |
|
372 | 0 | if (glyph >= GS_MIN_GLYPH_INDEX) |
373 | 0 | glyph -= GS_MIN_GLYPH_INDEX; |
374 | | |
375 | | /* guess if the font type is not truetype */ |
376 | 0 | if (pfont->FontType != ft_TrueType) { |
377 | 0 | glyph -= 29; |
378 | 0 | if (glyph < 258) { |
379 | 0 | pstr->data = (const byte *)pl_mac_names[glyph]; |
380 | 0 | pstr->size = strlen((const char *)pstr->data); |
381 | 0 | return 0; |
382 | 0 | } else { |
383 | 0 | if_debug1m('=', pfont->memory, |
384 | 0 | "[=]glyph index %lx out of range\n", (ulong) glyph); |
385 | 0 | return -1; |
386 | 0 | } |
387 | 0 | } |
388 | | |
389 | 0 | table_offset = |
390 | 0 | tt_find_table((gs_font_type42 *) pfont, "post", &table_length); |
391 | | /* no post table */ |
392 | 0 | if (table_offset == 0) |
393 | 0 | return -1; |
394 | | /* this shoudn't happen but... */ |
395 | | /* 32 byte offset, plus 2 bytes for number of glyphs |
396 | | less than that is deifnitely an invalid table. |
397 | | */ |
398 | 0 | if (table_length < 34) |
399 | 0 | return -1; |
400 | | |
401 | 0 | { |
402 | 0 | ulong format; |
403 | 0 | int numGlyphs; |
404 | 0 | int code; |
405 | 0 | uint glyph_name_index; |
406 | 0 | const byte *postp; /* post table pointer */ |
407 | |
|
408 | 0 | code = ((gs_font_type42 *) pfont)->data.string_proc((gs_font_type42 *) pfont, |
409 | 0 | table_offset, |
410 | 0 | table_length, &postp); |
411 | 0 | if (code < 0) |
412 | 0 | return -1; |
413 | | |
414 | 0 | format = u32(postp); |
415 | 0 | if (format != 0x20000) { |
416 | | /* format 1.0 (mac encoding) is a simple table see the TT |
417 | | spec. We don't implement this because we don't see it |
418 | | in practice */ |
419 | 0 | dmprintf1(pfont->memory, "unknown post table format %lX\n", |
420 | 0 | format); |
421 | 0 | return -1; |
422 | 0 | } |
423 | | /* skip over the post header */ |
424 | 0 | numGlyphs = (int)u16(postp + 32); |
425 | 0 | if ((int)glyph > numGlyphs - 1) { |
426 | 0 | if_debug1m('=', pfont->memory, |
427 | 0 | "[=]glyph index %lx out of range\n", glyph); |
428 | 0 | return -1; |
429 | 0 | } |
430 | | /* glyph name index starts at post + 34 each entry is 2 bytes */ |
431 | 0 | if (postp + 34 + (glyph * 2) + 2 > postp + table_length) |
432 | 0 | return -1; |
433 | | |
434 | 0 | glyph_name_index = u16(postp + 34 + (glyph * 2)); |
435 | | /* this shouldn't happen */ |
436 | 0 | if (glyph_name_index > 0x7fff) |
437 | 0 | return -1; |
438 | | /* mac easy */ |
439 | 0 | if (glyph_name_index < 258) { |
440 | |
|
441 | 0 | pstr->data = (const byte *)pl_mac_names[glyph_name_index]; |
442 | 0 | pstr->size = strlen((const char *)pstr->data); |
443 | 0 | return 0; |
444 | | /* not mac */ |
445 | 0 | } else { |
446 | 0 | byte *mydata; |
447 | | /* and here's the tricky part */ |
448 | 0 | const byte *pascal_stringp = postp + 34 + (numGlyphs * 2); |
449 | | /* 0 - 257 lives in the mac table above */ |
450 | 0 | glyph_name_index -= 258; |
451 | | /* The string we want is the index'th pascal string, |
452 | | so we "hop" to each length byte "index" times. */ |
453 | 0 | while (glyph_name_index > 0) { |
454 | 0 | pascal_stringp += ((int)(*pascal_stringp) + 1); |
455 | 0 | glyph_name_index--; |
456 | 0 | } |
457 | | /* length byte */ |
458 | 0 | pstr->size = (int)(*pascal_stringp); |
459 | | /* + 1 is for the length byte */ |
460 | 0 | pstr->data = pascal_stringp + 1; |
461 | | /* sanity check */ |
462 | 0 | if (pstr->data + pstr->size > postp + table_length || |
463 | 0 | pstr->data - 1 < postp) { |
464 | 0 | dmprintf(pfont->memory, "data out of range\n"); |
465 | 0 | return -1; |
466 | 0 | } |
467 | | /* sigh - we have to allocate a copy of the data - by the |
468 | | time a high level device makes use of it the font data |
469 | | may be freed. Track the allocated memory in our |
470 | | font 'wrapper' so we can free it when we free tha font wrapper. |
471 | | */ |
472 | 0 | mydata = |
473 | 0 | gs_alloc_bytes(pfont->memory, pstr->size + 1, |
474 | 0 | "glyph to name"); |
475 | 0 | if (mydata == 0) |
476 | 0 | return -1; |
477 | 0 | memcpy(mydata, pascal_stringp + 1, pstr->size); |
478 | 0 | pstr->data = mydata; |
479 | 0 | if (plfont->names == NULL) { |
480 | 0 | plfont->names = (char **)gs_alloc_bytes(pfont->memory, 256 * sizeof (char *), "names storage"); |
481 | 0 | if (plfont->names == NULL) { |
482 | 0 | gs_free_object(pfont->memory, (byte *)pstr->data, "free string on error"); |
483 | 0 | pstr->data = NULL; |
484 | 0 | pstr->size = 0; |
485 | 0 | return -1; |
486 | 0 | } |
487 | 0 | plfont->max_name_index = 255; |
488 | 0 | plfont->next_name_index = 0; |
489 | 0 | memset(plfont->names, 0x00, 256 * sizeof (char *)); |
490 | 0 | } |
491 | 0 | if (plfont->next_name_index > plfont->max_name_index) { |
492 | 0 | char **temp = NULL; |
493 | 0 | temp = (char **)gs_alloc_bytes(pfont->memory, (size_t)(plfont->max_name_index + 256) * sizeof (char *), "names storage"); |
494 | 0 | if (temp == NULL) { |
495 | 0 | gs_free_object(pfont->memory, (byte *)pstr->data, "free string on error"); |
496 | 0 | pstr->data = NULL; |
497 | 0 | pstr->size = 0; |
498 | 0 | return -1; |
499 | 0 | } |
500 | 0 | memset(temp, 0x00, (plfont->max_name_index + 256) * sizeof (char *)); |
501 | 0 | memcpy(temp, plfont->names, plfont->max_name_index * sizeof(char *)); |
502 | 0 | gs_free_object(pfont->memory, (void *)plfont->names, "realloc names storage"); |
503 | 0 | plfont->names = temp; |
504 | 0 | plfont->max_name_index += 256; |
505 | 0 | } |
506 | 0 | plfont->names[plfont->next_name_index++] = (char *)pstr->data; |
507 | 0 | return 0; |
508 | 0 | } |
509 | 0 | } |
510 | 0 | return 0; |
511 | 0 | } |
512 | | |
513 | | /* Get the unicode valude for a glyph */ |
514 | | static int |
515 | | pl_decode_glyph(gs_font * font, gs_glyph glyph, int ch, ushort *unicode_return, unsigned int length) |
516 | 0 | { |
517 | 0 | unsigned char *ucode = (unsigned char *)unicode_return; |
518 | |
|
519 | 0 | if (ch < 0 || ch > 255) |
520 | 0 | return (int) GS_NO_CHAR; |
521 | | |
522 | 0 | if (length == 0) |
523 | 0 | return 2; |
524 | | |
525 | | #if ARCH_IS_BIG_ENDIAN |
526 | | *unicode_return = (ushort)ch; |
527 | | #else |
528 | 0 | ucode[0] = 0x00; |
529 | 0 | ucode[1] = ch & 0xff; |
530 | 0 | #endif |
531 | 0 | return 2; |
532 | 0 | } |
533 | | |
534 | | /* ---------------- Width cache ---------------- */ |
535 | | static int |
536 | | pl_font_glyph_width_cache_node_add(pl_font_t *plfont, |
537 | | uint char_code, gs_point * pwidth) |
538 | 1.51M | { |
539 | 1.51M | pl_glyph_width_node_t *node; |
540 | | |
541 | | /* We can't safely cache widths for bitmap fonts */ |
542 | 1.51M | if (plfont->scaling_technology == plfst_bitmap) { |
543 | 0 | return(0); |
544 | 0 | } |
545 | | |
546 | 1.51M | if (plfont->widths_cache_nitems > PL_MAX_WIDTHS_CACHE_NITEMS) { |
547 | 573 | pl_font_glyph_width_cache_remove_nodes(plfont); |
548 | 573 | } |
549 | | |
550 | 1.51M | node = (pl_glyph_width_node_t *) gs_alloc_bytes(plfont->pfont->memory, |
551 | 1.51M | sizeof |
552 | 1.51M | (pl_glyph_width_node_t), |
553 | 1.51M | "pl_glyph_width_cache_node_add"); |
554 | | |
555 | 1.51M | if (node == NULL) { |
556 | | /* if we couldn't allocate a node, it probably doesn't hurt |
557 | | * to get rid of all the nodes we have. |
558 | | */ |
559 | 0 | pl_font_glyph_width_cache_remove_nodes(plfont); |
560 | 0 | return -1; |
561 | 0 | } |
562 | | |
563 | 1.51M | node->next = plfont->widths_cache; |
564 | 1.51M | plfont->widths_cache = node; |
565 | 1.51M | plfont->widths_cache_nitems++; |
566 | | |
567 | 1.51M | node->char_code = char_code; |
568 | 1.51M | node->font_id = plfont->pfont->id; |
569 | 1.51M | node->width = *pwidth; |
570 | | |
571 | 1.51M | return 0; |
572 | 1.51M | } |
573 | | |
574 | | |
575 | | static int |
576 | | pl_font_glyph_width_cache_node_search(const pl_font_t *plfont, uint char_code, |
577 | | gs_point * pwidth) |
578 | 28.4M | { |
579 | 28.4M | pl_glyph_width_node_t *current = plfont->widths_cache; |
580 | | |
581 | 1.87G | while (current) { |
582 | 1.87G | if (char_code == current->char_code) { |
583 | 26.4M | *pwidth = current->width; |
584 | 26.4M | return 0; |
585 | 26.4M | } |
586 | 1.84G | current = current->next; |
587 | 1.84G | } |
588 | 1.98M | return -1; |
589 | 28.4M | } |
590 | | |
591 | | |
592 | | /* ---------------- Public procedures ---------------- */ |
593 | | /* character width */ |
594 | | |
595 | | void |
596 | | pl_font_glyph_width_cache_remove_nodes(pl_font_t *plfont) |
597 | 2.22M | { |
598 | 2.22M | pl_glyph_width_node_t *current = plfont->widths_cache; |
599 | | |
600 | 3.74M | while (current) { |
601 | 1.51M | pl_glyph_width_node_t *next = current->next; |
602 | | |
603 | 1.51M | gs_free_object(plfont->pfont->memory, current, "pl_glyph_width_list_remove"); |
604 | 1.51M | current = next; |
605 | 1.51M | } |
606 | 2.22M | plfont->widths_cache = NULL; |
607 | 2.22M | plfont->widths_cache_nitems = 0; |
608 | 2.22M | return; |
609 | 2.22M | } |
610 | | |
611 | | int |
612 | | pl_font_char_width(const pl_font_t * plfont, const void *pgs, |
613 | | gs_char char_code, gs_point * pwidth) |
614 | 28.4M | { |
615 | 28.4M | int code = 0; |
616 | | |
617 | 28.4M | if (pl_font_glyph_width_cache_node_search(plfont, char_code, pwidth) >= 0) { |
618 | 26.4M | return(code); |
619 | 26.4M | } |
620 | | |
621 | 1.98M | if ((code = (*(plfont)->char_width) (plfont, pgs, char_code, pwidth)) == 0) { |
622 | | |
623 | | /* at least here, ignore the return value - if we fail to add a node |
624 | | * to the cache, we can reasonably attempt to carry on without it |
625 | | */ |
626 | 1.51M | (void)pl_font_glyph_width_cache_node_add((pl_font_t *)plfont, char_code, pwidth); |
627 | 1.51M | } |
628 | 1.98M | return code; |
629 | 28.4M | } |
630 | | |
631 | | /* character width */ |
632 | | int |
633 | | pl_font_char_metrics(const pl_font_t * plfont, const void *pgs, |
634 | | gs_char char_code, float metrics[4]) |
635 | 634k | { |
636 | 634k | return (*(plfont)->char_metrics) (plfont, pgs, char_code, metrics); |
637 | 634k | } |
638 | | |
639 | | /* Allocate a font. */ |
640 | | pl_font_t * |
641 | | pl_alloc_font(gs_memory_t * mem, client_name_t cname) |
642 | 1.97M | { |
643 | 1.97M | pl_font_t *plfont = gs_alloc_struct(mem, pl_font_t, &st_pl_font, cname); |
644 | | |
645 | 1.97M | if (plfont) { /* Initialize pointers. */ |
646 | 1.97M | plfont->pfont = 0; |
647 | 1.97M | plfont->header = 0; |
648 | 1.97M | plfont->glyphs.table = 0; |
649 | 1.97M | plfont->char_glyphs.table = 0; |
650 | | /* Initialize other defaults. */ |
651 | 1.97M | plfont->orient = 0; |
652 | 1.97M | plfont->allow_vertical_substitutes = false; |
653 | 1.97M | plfont->bold_fraction = 0; |
654 | 1.97M | plfont->font_file = 0; |
655 | 1.97M | plfont->resolution.x = plfont->resolution.y = 0; |
656 | 1.97M | plfont->params.proportional_spacing = true; |
657 | 1.97M | memset(plfont->character_complement, 0xff, 8); |
658 | 1.97M | plfont->offsets.GC = plfont->offsets.GT = plfont->offsets.VT = -1; |
659 | 1.97M | plfont->pts_per_inch = 72.0; /* normal value */ |
660 | 1.97M | plfont->widths_cache = NULL; |
661 | 1.97M | plfont->widths_cache_nitems = 0; |
662 | 1.97M | plfont->names = NULL; |
663 | 1.97M | plfont->max_name_index = 0; |
664 | 1.97M | plfont->next_name_index = 0; |
665 | 1.97M | } |
666 | 1.97M | return plfont; |
667 | 1.97M | } |
668 | | |
669 | | /* Structure descriptors for cloning fonts */ |
670 | | gs_private_st_ptrs1(st_pl_font_glyph_f, pl_font_glyph_t, "pl_font_glyph_t", |
671 | | pl_font_glyph_enum_ptrs_f, pl_font_glyph_reloc_ptrs_f, |
672 | | data); |
673 | | gs_private_st_element(st_pl_font_glyph_element_f, pl_font_glyph_t, |
674 | | "pl_font_glyph_t[]", pl_font_glyph_elt_enum_ptrs_f, |
675 | | pl_font_glyph_elt_reloc_ptrs_f, st_pl_font_glyph_f); |
676 | | |
677 | | pl_font_t * |
678 | | pl_clone_font(const pl_font_t * src, gs_memory_t * mem, client_name_t cname) |
679 | 0 | { |
680 | 0 | pl_font_t *plfont = gs_alloc_struct(mem, pl_font_t, &st_pl_font, cname); |
681 | |
|
682 | 0 | if (plfont == 0) |
683 | 0 | return 0; |
684 | | /* copy technology common parts */ |
685 | 0 | plfont->storage = src->storage; |
686 | 0 | plfont->header_size = src->header_size; |
687 | 0 | plfont->scaling_technology = src->scaling_technology; |
688 | 0 | plfont->is_xl_format = src->is_xl_format; |
689 | 0 | plfont->allow_vertical_substitutes = src->allow_vertical_substitutes; |
690 | 0 | plfont->font_type = src->font_type; |
691 | 0 | plfont->char_width = src->char_width; |
692 | 0 | plfont->char_metrics = src->char_metrics; |
693 | 0 | plfont->large_sizes = src->large_sizes; |
694 | 0 | plfont->resolution = src->resolution; |
695 | 0 | plfont->params = src->params; |
696 | 0 | plfont->pts_per_inch = src->pts_per_inch; |
697 | 0 | plfont->font_file_loaded = src->font_file_loaded; |
698 | 0 | plfont->orient = src->orient; |
699 | 0 | plfont->bold_fraction = src->bold_fraction; |
700 | 0 | plfont->widths_cache = NULL; |
701 | 0 | plfont->widths_cache_nitems = 0; |
702 | 0 | { |
703 | 0 | int i; |
704 | |
|
705 | 0 | for (i = 0; i < sizeof(src->character_complement); i++) |
706 | 0 | plfont->character_complement[i] = src->character_complement[i]; |
707 | 0 | } |
708 | 0 | plfont->offsets = src->offsets; |
709 | 0 | plfont->header = gs_alloc_bytes(mem, src->header_size, cname); |
710 | 0 | if (plfont->header == 0) |
711 | 0 | return 0; |
712 | 0 | memcpy(plfont->header, src->header, src->header_size); |
713 | |
|
714 | 0 | plfont->names = NULL; |
715 | 0 | plfont->max_name_index = 0; |
716 | 0 | plfont->next_name_index = 0; |
717 | |
|
718 | 0 | if (src->font_file) { |
719 | 0 | plfont->font_file = |
720 | 0 | (char *)gs_alloc_bytes(mem, strlen(src->font_file) + 1, |
721 | 0 | "pl_clone_font"); |
722 | 0 | if (plfont->font_file == 0) |
723 | 0 | return 0; /* #NB errors!!! */ |
724 | 0 | strcpy(plfont->font_file, src->font_file); |
725 | 0 | } else |
726 | 0 | plfont->font_file = 0; |
727 | | /* technology specific setup */ |
728 | 0 | switch (plfont->scaling_technology) { |
729 | 0 | case plfst_bitmap: |
730 | 0 | { |
731 | 0 | gs_font_base *pfont = |
732 | 0 | gs_alloc_struct(mem, gs_font_base, &st_gs_font_base, |
733 | 0 | cname); |
734 | 0 | if (pfont == 0) |
735 | 0 | return 0; |
736 | 0 | pl_fill_in_font((gs_font *) pfont, plfont, src->pfont->dir, |
737 | 0 | mem, "nameless_font"); |
738 | 0 | pl_fill_in_bitmap_font(pfont, gs_next_ids(mem, 1)); |
739 | 0 | break; |
740 | 0 | } |
741 | 0 | case plfst_Intellifont: |
742 | 0 | { |
743 | 0 | gs_font_base *pfont = |
744 | 0 | gs_alloc_struct(mem, gs_font_base, &st_gs_font_base, |
745 | 0 | cname); |
746 | 0 | if (pfont == 0) |
747 | 0 | return 0; |
748 | 0 | pl_fill_in_font((gs_font *) pfont, plfont, src->pfont->dir, |
749 | 0 | mem, "nameless_font"); |
750 | 0 | pl_fill_in_intelli_font(pfont, gs_next_ids(mem, 1)); |
751 | 0 | break; |
752 | 0 | } |
753 | 0 | case plfst_TrueType: |
754 | 0 | { |
755 | 0 | { |
756 | 0 | gs_font_type42 *pfont = |
757 | 0 | gs_alloc_struct(mem, gs_font_type42, |
758 | 0 | &st_gs_font_type42, cname); |
759 | | /* detect if a truetype font is downloaded or |
760 | | internal. There must be a better way... */ |
761 | 0 | gs_font_type42 *pfont_src = (gs_font_type42 *) src->pfont; |
762 | 0 | bool downloaded = |
763 | 0 | (pfont_src->data.get_outline == pl_tt_get_outline); |
764 | 0 | if (pfont == 0) |
765 | 0 | return 0; |
766 | 0 | pl_fill_in_font((gs_font *) pfont, plfont, |
767 | 0 | src->pfont->dir, mem, "nameless_font"); |
768 | 0 | pl_fill_in_tt_font(pfont, downloaded ? NULL : src->header, |
769 | 0 | gs_next_ids(mem, 1)); |
770 | 0 | } |
771 | 0 | break; |
772 | 0 | } |
773 | 0 | default: |
774 | 0 | return 0; |
775 | 0 | } |
776 | 0 | if (src->char_glyphs.table != 0) { |
777 | | /* HAS may gs_alloc_struct_array() here but this is |
778 | | consistant with pl_tt_alloc_char_glyphs() */ |
779 | 0 | pl_tt_char_glyph_t *char_glyphs = |
780 | 0 | (pl_tt_char_glyph_t *) gs_alloc_byte_array(mem, |
781 | 0 | src->char_glyphs.size, |
782 | 0 | sizeof |
783 | 0 | (pl_tt_char_glyph_t), |
784 | 0 | cname); |
785 | 0 | int i; |
786 | |
|
787 | 0 | if (char_glyphs == 0) |
788 | 0 | return 0; |
789 | 0 | for (i = 0; i < src->char_glyphs.size; i++) |
790 | 0 | char_glyphs[i] = src->char_glyphs.table[i]; |
791 | | /* once again a copy struct shortcut and then are restore |
792 | | of the char_glyphs.table pointer */ |
793 | 0 | plfont->char_glyphs = src->char_glyphs; |
794 | 0 | plfont->char_glyphs.table = char_glyphs; |
795 | 0 | } else /* no character glyph table data */ |
796 | 0 | plfont->char_glyphs = src->char_glyphs; |
797 | | |
798 | 0 | if (src->glyphs.table != 0) { |
799 | 0 | int i; |
800 | |
|
801 | 0 | plfont->glyphs.table = |
802 | 0 | gs_alloc_struct_array(mem, src->glyphs.size, pl_font_glyph_t, |
803 | 0 | &st_pl_font_glyph_element_f, cname); |
804 | 0 | if (plfont->glyphs.table == NULL) |
805 | 0 | return 0; |
806 | 0 | plfont->glyphs.used = src->glyphs.used; |
807 | 0 | plfont->glyphs.limit = src->glyphs.limit; |
808 | 0 | plfont->glyphs.size = src->glyphs.size; |
809 | 0 | plfont->glyphs.skip = src->glyphs.skip; |
810 | 0 | for (i = 0; i < src->glyphs.size; i++) { |
811 | 0 | const byte *data = src->glyphs.table[i].data; |
812 | 0 | byte *char_data; |
813 | |
|
814 | 0 | plfont->glyphs.table[i].glyph = src->glyphs.table[i].glyph; |
815 | 0 | plfont->glyphs.table[i].data = 0; |
816 | 0 | if (data) { |
817 | 0 | uint size = src->glyphs.table[i].data_len; |
818 | 0 | char_data = gs_alloc_bytes(mem, size, cname); |
819 | 0 | if (char_data == 0) |
820 | 0 | return 0; |
821 | 0 | memcpy(char_data, data, size); |
822 | 0 | plfont->glyphs.table[i].data = char_data; |
823 | 0 | plfont->glyphs.table[i].data_len = size; |
824 | 0 | } |
825 | |
|
826 | 0 | } |
827 | 0 | } else /* no glyph table */ |
828 | 0 | plfont->glyphs = src->glyphs; |
829 | 0 | return plfont; |
830 | 0 | } |
831 | | |
832 | | /* Fill in generic font boilerplate. NB TODO examine duplication with |
833 | | gs_font_alloc(). The font name must not contain spaces. It is |
834 | | used for PDF output and Acrobat (some versions) do not process the |
835 | | file correctly with spaces in the name. */ |
836 | | int |
837 | | pl_fill_in_font(gs_font * pfont, pl_font_t * plfont, gs_font_dir * pdir, |
838 | | gs_memory_t * mem, const char *font_name) |
839 | 2.03M | { |
840 | 2.03M | gs_font_base *pbfont = (gs_font_base *) pfont; |
841 | | |
842 | 2.03M | plfont->pfont = pfont; |
843 | | /* Initialize generic font data. */ |
844 | 2.03M | gs_make_identity(&pbfont->orig_FontMatrix); |
845 | 2.03M | gs_make_identity(&pbfont->FontMatrix); |
846 | 2.03M | pbfont->next = pbfont->prev = 0; |
847 | 2.03M | pbfont->memory = mem; |
848 | 2.03M | pbfont->dir = pdir; |
849 | 2.03M | pbfont->is_resource = false; |
850 | 2.03M | gs_notify_init(&pbfont->notify_list, gs_memory_stable(mem)); |
851 | 2.03M | pbfont->base = (gs_font *) pbfont; |
852 | 2.03M | pbfont->client_data = plfont; |
853 | 2.03M | pbfont->WMode = 0; |
854 | 2.03M | pbfont->PaintType = 0; |
855 | 2.03M | pbfont->StrokeWidth = 0; |
856 | 2.03M | pbfont->is_cached = 0; |
857 | 2.03M | pbfont->procs.init_fstack = gs_default_init_fstack; |
858 | 2.03M | pbfont->procs.next_char_glyph = gs_default_next_char_glyph; |
859 | 2.03M | pbfont->FAPI = NULL; |
860 | 2.03M | pbfont->FAPI_font_data = NULL; |
861 | | |
862 | 2.03M | pbfont->procs.glyph_name = pl_glyph_name; |
863 | 2.03M | pbfont->procs.decode_glyph = pl_decode_glyph; |
864 | | /* NB pbfont->procs.callbacks.known_encode = pl_known_encode; */ |
865 | 2.03M | pbfont->procs.define_font = gs_no_define_font; |
866 | 2.03M | pbfont->procs.make_font = gs_no_make_font; |
867 | 2.03M | pbfont->procs.font_info = gs_default_font_info; |
868 | 2.03M | pbfont->procs.glyph_info = gs_default_glyph_info; |
869 | 2.03M | pbfont->procs.glyph_outline = gs_no_glyph_outline; |
870 | 2.03M | pbfont->id = gs_next_ids(mem, 1); |
871 | 2.03M | { |
872 | 2.03M | size_t sz = strlen(font_name); |
873 | 2.03M | gs_font_name *fnm = &pbfont->font_name; |
874 | 2.03M | gs_font_name *knm = &pbfont->key_name; |
875 | | |
876 | 2.03M | if (sz > gs_font_name_max) |
877 | 0 | sz = gs_font_name_max; |
878 | 2.03M | fnm->size = knm->size = sz; |
879 | | |
880 | 2.03M | memcpy(fnm->chars, font_name, sz); |
881 | 2.03M | fnm->chars[sz] = 0; |
882 | | |
883 | 2.03M | memcpy(knm->chars, font_name, sz); |
884 | 2.03M | knm->chars[sz] = 0; |
885 | 2.03M | } |
886 | 2.03M | return 0; |
887 | 2.03M | } |
888 | | |
889 | | /* Fill in bitmap font boilerplate. */ |
890 | | void |
891 | | pl_fill_in_bitmap_font(gs_font_base * pfont, long unique_id) |
892 | 16.2k | { |
893 | 16.2k | pfont->FontType = ft_PCL_user_defined; |
894 | 16.2k | pfont->BitmapWidths = true; |
895 | 16.2k | pfont->ExactSize = fbit_use_bitmaps; |
896 | 16.2k | pfont->InBetweenSize = fbit_use_bitmaps; |
897 | 16.2k | pfont->TransformedChar = fbit_transform_bitmaps; |
898 | 16.2k | pl_bitmap_init_procs(pfont); |
899 | | /* We have no idea what the FontBBox should be. */ |
900 | 16.2k | pfont->FontBBox.p.x = pfont->FontBBox.p.y = |
901 | 16.2k | pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0; |
902 | 16.2k | uid_set_UniqueID(&pfont->UID, unique_id); |
903 | 16.2k | pfont->encoding_index = 1; /****** WRONG ******/ |
904 | 16.2k | pfont->nearest_encoding_index = 1; /****** WRONG ******/ |
905 | 16.2k | } |
906 | | |
907 | | /* Fill in TrueType font boilerplate. */ |
908 | | int |
909 | | pl_fill_in_tt_font(gs_font_type42 * pfont, void *data, long unique_id) |
910 | 1.95M | { |
911 | 1.95M | pfont->FontType = ft_TrueType; |
912 | 1.95M | pfont->BitmapWidths = true; |
913 | 1.95M | pfont->ExactSize = fbit_use_outlines; |
914 | 1.95M | pfont->InBetweenSize = fbit_use_outlines; |
915 | 1.95M | pfont->TransformedChar = fbit_use_outlines; |
916 | | /* Initialize base font data. */ |
917 | | /* |
918 | | * We can't set the FontBBox correctly until we've initialized the |
919 | | * Type 42 specific data, but we need to set it to an empty box now |
920 | | * for the sake of gs_type42_font_init. |
921 | | */ |
922 | 1.95M | pfont->FontBBox.p.x = pfont->FontBBox.p.y = |
923 | 1.95M | pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0; |
924 | 1.95M | uid_set_UniqueID(&pfont->UID, unique_id); |
925 | 1.95M | pfont->encoding_index = 1; /****** WRONG ******/ |
926 | 1.95M | pfont->nearest_encoding_index = 1; /****** WRONG ******/ |
927 | | /* Initialize Type 42 specific data. */ |
928 | 1.95M | pfont->data.proc_data = data; |
929 | 1.95M | pl_tt_init_procs(pfont); |
930 | 1.95M | { |
931 | 1.95M | int code = gs_type42_font_init(pfont, 0); |
932 | | |
933 | 1.95M | if (code < 0) |
934 | 15 | return code; |
935 | 1.95M | } |
936 | | /* disable unused FAPI */ |
937 | 1.95M | pfont->FAPI = 0; |
938 | 1.95M | pfont->FAPI_font_data = 0; |
939 | 1.95M | pl_tt_finish_init(pfont, !data); |
940 | 1.95M | return 0; |
941 | 1.95M | } |
942 | | |
943 | | /* Fill in Intellifont boilerplate. */ |
944 | | void |
945 | | pl_fill_in_intelli_font(gs_font_base * pfont, long unique_id) |
946 | 0 | { /* Intellifonts have an 8782-unit design space. */ |
947 | 0 | { |
948 | 0 | gs_matrix mat; |
949 | |
|
950 | 0 | gs_make_scaling(1.0 / 8782, 1.0 / 8782, &mat); |
951 | 0 | gs_matrix_translate(&mat, -2980.0, -5380.0, &pfont->orig_FontMatrix); |
952 | 0 | } |
953 | 0 | pfont->FontType = ft_MicroType; |
954 | 0 | pfont->BitmapWidths = true; |
955 | 0 | pfont->ExactSize = fbit_use_outlines; |
956 | 0 | pfont->InBetweenSize = fbit_use_outlines; |
957 | 0 | pfont->TransformedChar = fbit_use_outlines; |
958 | | /* We have no idea what the FontBBox should be. */ |
959 | 0 | pfont->FontBBox.p.x = pfont->FontBBox.p.y = |
960 | 0 | pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0; |
961 | 0 | uid_set_UniqueID(&pfont->UID, unique_id); |
962 | 0 | pfont->encoding_index = 1; /****** WRONG ******/ |
963 | 0 | pfont->nearest_encoding_index = 1; /****** WRONG ******/ |
964 | 0 | pl_intelli_init_procs(pfont); |
965 | 0 | } |
966 | | |
967 | | /* |
968 | | * Set large_sizes, scaling_technology, character_complement, offsets |
969 | | * (for TrueType fonts), and resolution (for bitmap fonts) by scanning |
970 | | * the segments of a segmented downloaded font. |
971 | | * This is used for PCL5 Format 15 and 16 fonts and for PCL XL fonts. |
972 | | * fst_offset is the offset of the Font Scaling Technology and Variety bytes; |
973 | | * the segment data runs from start_offset up to end_offset. |
974 | | * large_sizes = false indicates 2-byte segment sizes, true indicates 4-byte. |
975 | | */ |
976 | | int |
977 | | pl_font_scan_segments(const gs_memory_t * mem, |
978 | | pl_font_t * plfont, int fst_offset, int start_offset, |
979 | | long end_offset, bool large_sizes, |
980 | | const pl_font_offset_errors_t * pfoe) |
981 | 16.2k | { |
982 | 16.2k | const byte *header = plfont->header; |
983 | 16.2k | pl_font_scaling_technology_t fst = header[fst_offset]; |
984 | 16.2k | int wsize = (large_sizes ? 4 : 2); |
985 | 16.2k | const byte *segment = header + start_offset; |
986 | 16.2k | const byte *end = header + end_offset; |
987 | 16.2k | const byte *null_segment = end - (2 + wsize); |
988 | 16.2k | bool found = false; |
989 | 16.2k | ulong seg_size; |
990 | 16.2k | int illegal_font_data = pfoe->illegal_font_data; |
991 | | |
992 | 16.2k | #define return_scan_error(err)\ |
993 | 16.2k | return_error((err) ? (err) : illegal_font_data); |
994 | | |
995 | 16.2k | if (memcmp(null_segment, "\377\377", 2) /* NULL segment header */ ) |
996 | 16.2k | return_scan_error(pfoe->missing_required_segment); |
997 | 16.2k | if (memcmp(null_segment + 2, "\0\0\0\0", wsize) /* NULL segment size */ ) |
998 | 16.2k | return_scan_error(pfoe->illegal_null_segment_size); |
999 | 16.2k | switch (fst) { |
1000 | 16.1k | case plfst_bitmap: |
1001 | 16.2k | case plfst_TrueType: |
1002 | 16.2k | break; |
1003 | 0 | default: |
1004 | 0 | return_scan_error(pfoe->illegal_font_header_fields); |
1005 | 16.2k | } |
1006 | 16.2k | if (header[fst_offset + 1]) /* variety, must be 0 */ |
1007 | 16.2k | return_scan_error(pfoe->illegal_font_header_fields); |
1008 | | /* Scan the segments. */ |
1009 | 48.6k | for (; end - segment >= 2 + wsize; segment += 2 + wsize + seg_size) { |
1010 | 32.4k | uint seg_id = u16(segment); |
1011 | 32.4k | const byte *sdata = segment + 2 + wsize; |
1012 | | |
1013 | 32.4k | #define id2(c1,c2) (((uint)(c1) << 8) + (c2)) |
1014 | | |
1015 | 32.4k | seg_size = (large_sizes ? u32(segment + 2) : u16(segment + 2)); |
1016 | 32.4k | if (seg_size + 2 + wsize > end - segment) |
1017 | 2 | return_error(illegal_font_data); |
1018 | | /* Handle segments common to all fonts. */ |
1019 | 32.4k | switch (seg_id) { |
1020 | 16.2k | case 0xffff: /* NULL segment ID */ |
1021 | 16.2k | if (segment != null_segment) |
1022 | 0 | return_error(illegal_font_data); |
1023 | 16.2k | continue; |
1024 | 16.2k | case id2('V', 'I'): |
1025 | 0 | continue; |
1026 | 0 | case id2('C', 'C'): |
1027 | 0 | if (seg_size != 8) |
1028 | 0 | return_error(illegal_font_data); |
1029 | 0 | memcpy(plfont->character_complement, sdata, 8); |
1030 | 0 | continue; |
1031 | 16.2k | default: |
1032 | 16.2k | ; |
1033 | 32.4k | } |
1034 | | /* Handle segments specific to the scaling technology. */ |
1035 | 16.2k | if (fst == plfst_bitmap) |
1036 | 16.1k | switch (seg_id) { |
1037 | 16.1k | case id2('B', 'R'): |
1038 | 16.1k | if (seg_size != 4) |
1039 | 16.1k | return_scan_error(pfoe->illegal_BR_segment); |
1040 | 16.1k | { |
1041 | 16.1k | uint xres = pl_get_uint16(sdata); |
1042 | 16.1k | uint yres = pl_get_uint16(sdata + 2); |
1043 | | |
1044 | 16.1k | if (xres == 0 || yres == 0) |
1045 | 16.1k | return_scan_error(pfoe->illegal_BR_segment); |
1046 | 16.1k | plfont->resolution.x = xres; |
1047 | 16.1k | plfont->resolution.y = yres; |
1048 | 16.1k | } |
1049 | 16.1k | found = true; |
1050 | 16.1k | break; |
1051 | 0 | default: |
1052 | 0 | if (pfoe->illegal_font_segment < 0) |
1053 | 0 | return_error(pfoe->illegal_font_segment); |
1054 | 16.1k | } else /* fst == plfst_TrueType */ |
1055 | 93 | switch (seg_id) { |
1056 | 93 | case id2('G', 'T'): |
1057 | | /* |
1058 | | * We don't do much checking here, but we do check that |
1059 | | * the segment starts with a table directory that |
1060 | | * includes at least 3 elements (gdir, head, |
1061 | | * maxp -- but we don't check the actual names). |
1062 | | */ |
1063 | 93 | if (seg_size < 12 + 5 * 16 || |
1064 | | /* memcmp(sdata, "\000\001\000\000", 4) || */ |
1065 | 93 | u16(sdata + 4) < 3) |
1066 | 93 | return_scan_error(pfoe->illegal_GT_segment); |
1067 | 93 | plfont->offsets.GT = segment - header; |
1068 | 93 | found = true; |
1069 | 93 | break; |
1070 | 0 | case id2('G', 'C'): |
1071 | 0 | if (seg_size < 6 || u16(sdata) != 0 || |
1072 | 0 | seg_size != u16(sdata + 4) * 6 + 6) |
1073 | 0 | return_scan_error(pfoe->illegal_GC_segment); |
1074 | 0 | plfont->offsets.GC = segment - header; |
1075 | 0 | break; |
1076 | 0 | case id2('V', 'T'): |
1077 | | /* Check for end of table mark */ |
1078 | 0 | if ((seg_size & 3) != 0 || seg_size < 4 || |
1079 | 0 | u16(sdata + seg_size - 4) != 0xffff) |
1080 | 0 | return_scan_error(pfoe->illegal_VT_segment); |
1081 | | /* Check for table sorted by horizontal glyph ID */ |
1082 | 0 | { |
1083 | 0 | uint i; |
1084 | |
|
1085 | 0 | for (i = 0; i < seg_size - 4; i += 4) |
1086 | 0 | if (u16(sdata + i) > u16(sdata + i + 4)) |
1087 | 0 | return_scan_error(pfoe->illegal_VT_segment); |
1088 | 0 | } |
1089 | 0 | plfont->offsets.VT = segment - header; |
1090 | 0 | break; |
1091 | 0 | case id2('V', 'E'): /* nb unimplemented */ |
1092 | 0 | break; |
1093 | 0 | case id2('V', 'R'): /* nb unimplemented */ |
1094 | 0 | break; |
1095 | 0 | case id2('C', 'E'): /* nb unimplemented */ |
1096 | 0 | break; |
1097 | 0 | default: |
1098 | 0 | if (pfoe->illegal_font_segment < 0) |
1099 | 0 | return_error(pfoe->illegal_font_segment); |
1100 | 93 | } |
1101 | 16.2k | #undef id2 |
1102 | 16.2k | } |
1103 | 16.2k | if (!found) |
1104 | 16.2k | return_scan_error(pfoe->missing_required_segment); |
1105 | 16.2k | if (segment != end) |
1106 | 0 | return_error(illegal_font_data); |
1107 | 16.2k | plfont->large_sizes = large_sizes; |
1108 | 16.2k | plfont->scaling_technology = fst; |
1109 | 16.2k | return 0; |
1110 | 16.2k | #undef return_scan_error |
1111 | 16.2k | } |
1112 | | |
1113 | | int |
1114 | | pl_free_tt_fontfile_buffer(gs_memory_t * mem, byte * ptt_font_data) |
1115 | 0 | { |
1116 | 0 | gs_free_object(mem, ptt_font_data, "pl_tt_load_font data"); |
1117 | 0 | return 0; |
1118 | 0 | } |
1119 | | |
1120 | | int |
1121 | | pl_alloc_tt_fontfile_buffer(stream * in, gs_memory_t * mem, |
1122 | | byte ** pptt_font_data, ulong * size) |
1123 | 1.95M | { |
1124 | 1.95M | ulong len = (sfseek(in, 0L, SEEK_END), sftell(in)); |
1125 | | |
1126 | 1.95M | *size = 6 + len; /* leave room for segment header */ |
1127 | 1.95M | if (*size != (uint) (*size)) { |
1128 | | /* |
1129 | | * The font is too big to load in a single piece -- punt. |
1130 | | * The error message is bogus, but there isn't any more |
1131 | | * appropriate one. |
1132 | | */ |
1133 | 0 | sfclose(in); |
1134 | 0 | return_error(gs_error_VMerror); |
1135 | 0 | } |
1136 | 1.95M | srewind(in); |
1137 | 1.95M | *pptt_font_data = gs_alloc_bytes(mem, *size, "pl_tt_load_font data"); |
1138 | 1.95M | if (*pptt_font_data == 0) { |
1139 | 0 | sfclose(in); |
1140 | 0 | return_error(gs_error_VMerror); |
1141 | 0 | } |
1142 | 1.95M | sfread(*pptt_font_data + 6, 1, len, in); |
1143 | 1.95M | sfclose(in); |
1144 | 1.95M | return 0; |
1145 | 1.95M | } |
1146 | | |
1147 | | /* Load a built-in (TrueType) font from external storage. */ |
1148 | | int |
1149 | | pl_load_tt_font(stream * in, gs_font_dir * pdir, gs_memory_t * mem, |
1150 | | long unique_id, pl_font_t ** pplfont, char *font_name) |
1151 | 1.95M | { |
1152 | 1.95M | byte *tt_font_datap = NULL; |
1153 | 1.95M | ulong size; |
1154 | 1.95M | int code; |
1155 | 1.95M | gs_font_type42 *pfont = NULL; |
1156 | 1.95M | pl_font_t *plfont = NULL; |
1157 | 1.95M | byte *file_name = NULL; |
1158 | 1.95M | gs_const_string pfname; |
1159 | | |
1160 | 1.95M | if (sfilename(in, &pfname) == 0) { |
1161 | 1.95M | file_name = |
1162 | 1.95M | gs_alloc_bytes(mem, pfname.size + 1, "pl_load_tt_font file_name"); |
1163 | 1.95M | if (!file_name) { |
1164 | 0 | sfclose(in); |
1165 | 0 | return_error(gs_error_VMerror); |
1166 | 0 | } |
1167 | | /* the stream code guarantees the string is null terminated */ |
1168 | 1.95M | memcpy(file_name, pfname.data, pfname.size + 1); |
1169 | 1.95M | } |
1170 | | |
1171 | | /* get the data from the file */ |
1172 | 1.95M | code = pl_alloc_tt_fontfile_buffer(in, mem, &tt_font_datap, &size); |
1173 | 1.95M | if (code < 0) |
1174 | 0 | goto error; |
1175 | | /* Make a Type 42 font out of the TrueType data. */ |
1176 | 1.95M | pfont = gs_alloc_struct(mem, gs_font_type42, &st_gs_font_type42, |
1177 | 1.95M | "pl_tt_load_font(gs_font_type42)"); |
1178 | 1.95M | if (pfont == NULL) { |
1179 | 0 | code = gs_error_VMerror; |
1180 | 0 | goto error; |
1181 | 0 | } |
1182 | 1.95M | memset(pfont, 0, sizeof(*pfont)); |
1183 | 1.95M | plfont = pl_alloc_font(mem, "pl_tt_load_font(pl_font_t)"); |
1184 | 1.95M | if (plfont == NULL) { |
1185 | 0 | code = gs_error_VMerror; |
1186 | 0 | goto error; |
1187 | 0 | } |
1188 | | |
1189 | | /* Initialize general font boilerplate. */ |
1190 | 1.95M | code = pl_fill_in_font((gs_font *) pfont, plfont, pdir, mem, font_name); |
1191 | 1.95M | if (code < 0) |
1192 | 0 | goto error; |
1193 | | |
1194 | | /* Initialize TrueType font boilerplate. */ |
1195 | 1.95M | plfont->header = tt_font_datap; |
1196 | 1.95M | plfont->header_size = size; |
1197 | 1.95M | plfont->scaling_technology = plfst_TrueType; |
1198 | 1.95M | plfont->font_type = plft_Unicode; |
1199 | 1.95M | plfont->large_sizes = true; |
1200 | 1.95M | plfont->offsets.GT = 0; |
1201 | 1.95M | plfont->is_xl_format = false; |
1202 | 1.95M | code = pl_fill_in_tt_font(pfont, tt_font_datap, unique_id); |
1203 | 1.95M | if (code < 0) |
1204 | 0 | goto error; |
1205 | 1.95M | code = gs_definefont(pdir, (gs_font *) pfont); |
1206 | 1.95M | if (code < 0) |
1207 | 0 | goto error; |
1208 | | |
1209 | 1.95M | code = pl_fapi_passfont(plfont, 0, NULL, (char *)file_name, NULL, 0); |
1210 | 1.95M | if (code < 0) |
1211 | 0 | goto error; |
1212 | 1.95M | if (file_name) |
1213 | 1.95M | gs_free_object(mem, file_name, "pl_load_tt_font file_name"); |
1214 | | |
1215 | 1.95M | *pplfont = plfont; |
1216 | 1.95M | return 0; |
1217 | | |
1218 | 0 | error: |
1219 | 0 | gs_free_object(mem, plfont, "pl_tt_load_font(pl_font_t)"); |
1220 | 0 | gs_free_object(mem, pfont, "pl_tt_load_font(gs_font_type42)"); |
1221 | 0 | pl_free_tt_fontfile_buffer(mem, tt_font_datap); |
1222 | 0 | gs_free_object(mem, file_name, "pl_load_tt_font file_name"); |
1223 | 0 | return_error(code); |
1224 | 1.95M | } |
1225 | | |
1226 | | /* load resident font data to ram */ |
1227 | | int |
1228 | | pl_load_resident_font_data_from_file(gs_memory_t * mem, pl_font_t * plfont) |
1229 | 1.47M | { |
1230 | | |
1231 | 1.47M | ulong len, size; |
1232 | 1.47M | byte *data; |
1233 | | |
1234 | 1.47M | if (plfont->font_file && !plfont->font_file_loaded) { |
1235 | 40.5k | stream *in = sfopen(plfont->font_file, "r", mem); |
1236 | | |
1237 | 40.5k | if (in == NULL) |
1238 | 0 | return -1; |
1239 | | /* note this is exactly the same as the code in pl_load_tt_font */ |
1240 | 40.5k | len = (sfseek(in, 0L, SEEK_END), sftell(in)); |
1241 | 40.5k | size = 6 + len; /* leave room for segment header */ |
1242 | | |
1243 | 40.5k | if (size != (uint) size) { |
1244 | | /* |
1245 | | * The font is too big to load in a single piece -- punt. |
1246 | | * The error message is bogus, but there isn't any more |
1247 | | * appropriate one. |
1248 | | */ |
1249 | 0 | sfclose(in); |
1250 | 0 | return_error(gs_error_VMerror); |
1251 | 0 | } |
1252 | 40.5k | srewind(in); |
1253 | 40.5k | data = gs_alloc_bytes(mem, size, "pl_tt_load_font data"); |
1254 | 40.5k | if (data == 0) { |
1255 | 0 | sfclose(in); |
1256 | 0 | return_error(gs_error_VMerror); |
1257 | 0 | } |
1258 | 40.5k | sfread(data + 6, 1, len, in); |
1259 | 40.5k | sfclose(in); |
1260 | 40.5k | plfont->header = data; |
1261 | 40.5k | plfont->header_size = size; |
1262 | 40.5k | plfont->font_file_loaded = true; |
1263 | 40.5k | } |
1264 | 1.47M | return 0; |
1265 | 1.47M | } |
1266 | | |
1267 | | /* Keep resident font data in (header) and deallocate the memory */ |
1268 | | int |
1269 | | pl_store_resident_font_data_in_file(char *font_file, gs_memory_t * mem, |
1270 | | pl_font_t * plfont) |
1271 | 1.64M | { |
1272 | | /* Free the header data */ |
1273 | 1.64M | if (plfont->header) { |
1274 | 1.64M | gs_free_object(mem, plfont->header, |
1275 | 1.64M | "pl_store_resident_font_data_in_file"); |
1276 | 1.64M | plfont->header = 0; |
1277 | 1.64M | plfont->header_size = 0; |
1278 | 1.64M | } else { |
1279 | | /* nothing to do */ |
1280 | 0 | return 0; |
1281 | 0 | } |
1282 | | /* we don't yet have a filename for this font object. create one |
1283 | | and store it in the font. */ |
1284 | 1.64M | if (!plfont->font_file) { |
1285 | 1.64M | plfont->font_file = |
1286 | 1.64M | (char *)gs_alloc_bytes(mem, strlen(font_file) + 1, |
1287 | 1.64M | "pl_store_resident_font_data_in_file"); |
1288 | 1.64M | if (plfont->font_file == 0) |
1289 | 0 | return -1; |
1290 | 1.64M | strcpy(plfont->font_file, font_file); |
1291 | 1.64M | } |
1292 | | /* designate that the font data is not in RAM */ |
1293 | 1.64M | plfont->font_file_loaded = false; |
1294 | 1.64M | return 0; |
1295 | 1.64M | } |
1296 | | |
1297 | | pl_font_t * |
1298 | | pl_lookup_font_by_pjl_number(pl_dict_t * pfontdict, int pjl_font_number) |
1299 | 310k | { |
1300 | 310k | pl_dict_enum_t dictp; |
1301 | 310k | gs_const_string key; |
1302 | 310k | void *value; |
1303 | | |
1304 | 310k | pl_dict_enum_begin(pfontdict, &dictp); |
1305 | 15.9M | while (pl_dict_enum_next(&dictp, &key, &value)) { |
1306 | 15.9M | pl_font_t *plfont = value; |
1307 | | |
1308 | 15.9M | if (plfont->params.pjl_font_number == pjl_font_number) |
1309 | 310k | return value; |
1310 | 15.9M | } |
1311 | 0 | return (pl_font_t *) NULL; |
1312 | 310k | } |