/src/ghostpdl/pcl/pl/plfont.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2025 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 | 24.5k | #define u16(bptr) pl_get_uint16(bptr) |
49 | | #define s16(bptr) pl_get_int16(bptr) |
50 | | /**** ASSUME uint >= 32 BITS ****/ |
51 | 24.5k | #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.09M | { |
58 | 1.09M | pl_font_t *plfont = plf; |
59 | | |
60 | | /* Free the characters. */ |
61 | 1.09M | if (!plfont->data_are_permanent) { |
62 | 1.08M | if (plfont->glyphs.table) { |
63 | 373 | uint i; |
64 | | |
65 | 114k | for (i = plfont->glyphs.size; i > 0;) { |
66 | 113k | void *data = (void *)plfont->glyphs.table[--i].data; |
67 | | |
68 | 113k | if (data) |
69 | 2.02k | gs_free_object(mem, data, cname); |
70 | 113k | } |
71 | 373 | } |
72 | 1.08M | gs_free_object(mem, (void *)plfont->header, cname); |
73 | 1.08M | plfont->header = 0; /* see hack note above */ |
74 | 1.08M | } |
75 | | |
76 | | /* free any nodes in the widths cache */ |
77 | 1.09M | pl_font_glyph_width_cache_remove_nodes(plfont); |
78 | | |
79 | | /* Free the font data itself. */ |
80 | 1.09M | gs_free_object(mem, (void *)plfont->char_glyphs.table, cname); |
81 | 1.09M | gs_free_object(mem, (void *)plfont->glyphs.table, cname); |
82 | 1.09M | if (plfont->pfont) { /* might be only partially constructed */ |
83 | 1.09M | gs_purge_font_from_char_caches_completely(plfont->pfont); |
84 | 1.09M | (void)gs_purge_font(plfont->pfont); |
85 | 1.09M | gs_free_object(mem, plfont->pfont, cname); |
86 | 1.09M | } |
87 | 1.09M | if (plfont->font_file) { |
88 | 825k | gs_free_object(mem, plfont->font_file, cname); |
89 | 825k | plfont->font_file = 0; |
90 | 825k | } |
91 | 1.09M | 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.09M | gs_free_object(mem, plf, cname); |
100 | 1.09M | } |
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 | 0 | if (table_length == 0) |
396 | 0 | return -1; |
397 | | |
398 | 0 | { |
399 | 0 | ulong format; |
400 | 0 | int numGlyphs; |
401 | 0 | uint glyph_name_index; |
402 | 0 | const byte *postp; /* post table pointer */ |
403 | |
|
404 | 0 | ((gs_font_type42 *) pfont)->data.string_proc((gs_font_type42 *) pfont, |
405 | 0 | table_offset, |
406 | 0 | table_length, &postp); |
407 | 0 | format = u32(postp); |
408 | 0 | if (format != 0x20000) { |
409 | | /* format 1.0 (mac encoding) is a simple table see the TT |
410 | | spec. We don't implement this because we don't see it |
411 | | in practice */ |
412 | 0 | dmprintf1(pfont->memory, "unknown post table format %lX\n", |
413 | 0 | format); |
414 | 0 | return -1; |
415 | 0 | } |
416 | | /* skip over the post header */ |
417 | 0 | numGlyphs = (int)u16(postp + 32); |
418 | 0 | if ((int)glyph > numGlyphs - 1) { |
419 | 0 | if_debug1m('=', pfont->memory, |
420 | 0 | "[=]glyph index %lx out of range\n", glyph); |
421 | 0 | return -1; |
422 | 0 | } |
423 | | /* glyph name index starts at post + 34 each entry is 2 bytes */ |
424 | 0 | glyph_name_index = u16(postp + 34 + (glyph * 2)); |
425 | | /* this shouldn't happen */ |
426 | 0 | if (glyph_name_index > 0x7fff) |
427 | 0 | return -1; |
428 | | /* mac easy */ |
429 | 0 | if (glyph_name_index < 258) { |
430 | |
|
431 | 0 | pstr->data = (const byte *)pl_mac_names[glyph_name_index]; |
432 | 0 | pstr->size = strlen((const char *)pstr->data); |
433 | 0 | return 0; |
434 | | /* not mac */ |
435 | 0 | } else { |
436 | 0 | byte *mydata; |
437 | | /* and here's the tricky part */ |
438 | 0 | const byte *pascal_stringp = postp + 34 + (numGlyphs * 2); |
439 | | /* 0 - 257 lives in the mac table above */ |
440 | 0 | glyph_name_index -= 258; |
441 | | /* The string we want is the index'th pascal string, |
442 | | so we "hop" to each length byte "index" times. */ |
443 | 0 | while (glyph_name_index > 0) { |
444 | 0 | pascal_stringp += ((int)(*pascal_stringp) + 1); |
445 | 0 | glyph_name_index--; |
446 | 0 | } |
447 | | /* length byte */ |
448 | 0 | pstr->size = (int)(*pascal_stringp); |
449 | | /* + 1 is for the length byte */ |
450 | 0 | pstr->data = pascal_stringp + 1; |
451 | | /* sanity check */ |
452 | 0 | if (pstr->data + pstr->size > postp + table_length || |
453 | 0 | pstr->data - 1 < postp) { |
454 | 0 | dmprintf(pfont->memory, "data out of range\n"); |
455 | 0 | return -1; |
456 | 0 | } |
457 | | /* sigh - we have to allocate a copy of the data - by the |
458 | | time a high level device makes use of it the font data |
459 | | may be freed. Track the allocated memory in our |
460 | | font 'wrapper' so we can free it when we free tha font wrapper. |
461 | | */ |
462 | 0 | mydata = |
463 | 0 | gs_alloc_bytes(pfont->memory, pstr->size + 1, |
464 | 0 | "glyph to name"); |
465 | 0 | if (mydata == 0) |
466 | 0 | return -1; |
467 | 0 | memcpy(mydata, pascal_stringp + 1, pstr->size); |
468 | 0 | pstr->data = mydata; |
469 | 0 | if (plfont->names == NULL) { |
470 | 0 | plfont->names = (char **)gs_alloc_bytes(pfont->memory, 256 * sizeof (char *), "names storage"); |
471 | 0 | if (plfont->names == NULL) { |
472 | 0 | gs_free_object(pfont->memory, (byte *)pstr->data, "free string on error"); |
473 | 0 | pstr->data = NULL; |
474 | 0 | pstr->size = 0; |
475 | 0 | return -1; |
476 | 0 | } |
477 | 0 | plfont->max_name_index = 255; |
478 | 0 | plfont->next_name_index = 0; |
479 | 0 | memset(plfont->names, 0x00, 256 * sizeof (char *)); |
480 | 0 | } |
481 | 0 | if (plfont->next_name_index > plfont->max_name_index) { |
482 | 0 | char **temp = NULL; |
483 | 0 | temp = (char **)gs_alloc_bytes(pfont->memory, (size_t)(plfont->max_name_index + 256) * sizeof (char *), "names storage"); |
484 | 0 | if (temp == NULL) { |
485 | 0 | gs_free_object(pfont->memory, (byte *)pstr->data, "free string on error"); |
486 | 0 | pstr->data = NULL; |
487 | 0 | pstr->size = 0; |
488 | 0 | return -1; |
489 | 0 | } |
490 | 0 | memset(temp, 0x00, (plfont->max_name_index + 256) * sizeof (char *)); |
491 | 0 | memcpy(temp, plfont->names, plfont->max_name_index * sizeof(char *)); |
492 | 0 | gs_free_object(pfont->memory, (void *)plfont->names, "realloc names storage"); |
493 | 0 | plfont->names = temp; |
494 | 0 | plfont->max_name_index += 256; |
495 | 0 | } |
496 | 0 | plfont->names[plfont->next_name_index++] = (char *)pstr->data; |
497 | 0 | return 0; |
498 | 0 | } |
499 | 0 | } |
500 | 0 | return 0; |
501 | 0 | } |
502 | | |
503 | | /* Get the unicode valude for a glyph */ |
504 | | static int |
505 | | pl_decode_glyph(gs_font * font, gs_glyph glyph, int ch, ushort *unicode_return, unsigned int length) |
506 | 0 | { |
507 | 0 | unsigned char *ucode = (unsigned char *)unicode_return; |
508 | |
|
509 | 0 | if (ch < 0 || ch > 255) |
510 | 0 | return (int) GS_NO_CHAR; |
511 | | |
512 | 0 | if (length == 0) |
513 | 0 | return 2; |
514 | | |
515 | | #if ARCH_IS_BIG_ENDIAN |
516 | | *unicode_return = (ushort)ch; |
517 | | #else |
518 | 0 | ucode[0] = 0x00; |
519 | 0 | ucode[1] = ch & 0xff; |
520 | 0 | #endif |
521 | 0 | return 2; |
522 | 0 | } |
523 | | |
524 | | /* ---------------- Width cache ---------------- */ |
525 | | static int |
526 | | pl_font_glyph_width_cache_node_add(pl_font_t *plfont, |
527 | | uint char_code, gs_point * pwidth) |
528 | 1.26M | { |
529 | 1.26M | pl_glyph_width_node_t *node; |
530 | | |
531 | | /* We can't safely cache widths for bitmap fonts */ |
532 | 1.26M | if (plfont->scaling_technology == plfst_bitmap) { |
533 | 0 | return(0); |
534 | 0 | } |
535 | | |
536 | 1.26M | if (plfont->widths_cache_nitems > PL_MAX_WIDTHS_CACHE_NITEMS) { |
537 | 31 | pl_font_glyph_width_cache_remove_nodes(plfont); |
538 | 31 | } |
539 | | |
540 | 1.26M | node = (pl_glyph_width_node_t *) gs_alloc_bytes(plfont->pfont->memory, |
541 | 1.26M | sizeof |
542 | 1.26M | (pl_glyph_width_node_t), |
543 | 1.26M | "pl_glyph_width_cache_node_add"); |
544 | | |
545 | 1.26M | if (node == NULL) { |
546 | | /* if we couldn't allocate a node, it probably doesn't hurt |
547 | | * to get rid of all the nodes we have. |
548 | | */ |
549 | 0 | pl_font_glyph_width_cache_remove_nodes(plfont); |
550 | 0 | return -1; |
551 | 0 | } |
552 | | |
553 | 1.26M | node->next = plfont->widths_cache; |
554 | 1.26M | plfont->widths_cache = node; |
555 | 1.26M | plfont->widths_cache_nitems++; |
556 | | |
557 | 1.26M | node->char_code = char_code; |
558 | 1.26M | node->font_id = plfont->pfont->id; |
559 | 1.26M | node->width = *pwidth; |
560 | | |
561 | 1.26M | return 0; |
562 | 1.26M | } |
563 | | |
564 | | |
565 | | static int |
566 | | pl_font_glyph_width_cache_node_search(const pl_font_t *plfont, uint char_code, |
567 | | gs_point * pwidth) |
568 | 14.7M | { |
569 | 14.7M | pl_glyph_width_node_t *current = plfont->widths_cache; |
570 | | |
571 | 1.30G | while (current) { |
572 | 1.29G | if (char_code == current->char_code) { |
573 | 13.4M | *pwidth = current->width; |
574 | 13.4M | return 0; |
575 | 13.4M | } |
576 | 1.28G | current = current->next; |
577 | 1.28G | } |
578 | 1.35M | return -1; |
579 | 14.7M | } |
580 | | |
581 | | |
582 | | /* ---------------- Public procedures ---------------- */ |
583 | | /* character width */ |
584 | | |
585 | | void |
586 | | pl_font_glyph_width_cache_remove_nodes(pl_font_t *plfont) |
587 | 1.33M | { |
588 | 1.33M | pl_glyph_width_node_t *current = plfont->widths_cache; |
589 | | |
590 | 2.60M | while (current) { |
591 | 1.26M | pl_glyph_width_node_t *next = current->next; |
592 | | |
593 | 1.26M | gs_free_object(plfont->pfont->memory, current, "pl_glyph_width_list_remove"); |
594 | 1.26M | current = next; |
595 | 1.26M | } |
596 | 1.33M | plfont->widths_cache = NULL; |
597 | 1.33M | plfont->widths_cache_nitems = 0; |
598 | 1.33M | return; |
599 | 1.33M | } |
600 | | |
601 | | int |
602 | | pl_font_char_width(const pl_font_t * plfont, const void *pgs, |
603 | | gs_char char_code, gs_point * pwidth) |
604 | 14.7M | { |
605 | 14.7M | int code = 0; |
606 | | |
607 | 14.7M | if (pl_font_glyph_width_cache_node_search(plfont, char_code, pwidth) >= 0) { |
608 | 13.4M | return(code); |
609 | 13.4M | } |
610 | | |
611 | 1.35M | if ((code = (*(plfont)->char_width) (plfont, pgs, char_code, pwidth)) == 0) { |
612 | | |
613 | | /* at least here, ignore the return value - if we fail to add a node |
614 | | * to the cache, we can reasonably attempt to carry on without it |
615 | | */ |
616 | 1.26M | (void)pl_font_glyph_width_cache_node_add((pl_font_t *)plfont, char_code, pwidth); |
617 | 1.26M | } |
618 | 1.35M | return code; |
619 | 14.7M | } |
620 | | |
621 | | /* character width */ |
622 | | int |
623 | | pl_font_char_metrics(const pl_font_t * plfont, const void *pgs, |
624 | | gs_char char_code, float metrics[4]) |
625 | 442k | { |
626 | 442k | return (*(plfont)->char_metrics) (plfont, pgs, char_code, metrics); |
627 | 442k | } |
628 | | |
629 | | /* Allocate a font. */ |
630 | | pl_font_t * |
631 | | pl_alloc_font(gs_memory_t * mem, client_name_t cname) |
632 | 1.09M | { |
633 | 1.09M | pl_font_t *plfont = gs_alloc_struct(mem, pl_font_t, &st_pl_font, cname); |
634 | | |
635 | 1.09M | if (plfont) { /* Initialize pointers. */ |
636 | 1.09M | plfont->pfont = 0; |
637 | 1.09M | plfont->header = 0; |
638 | 1.09M | plfont->glyphs.table = 0; |
639 | 1.09M | plfont->char_glyphs.table = 0; |
640 | | /* Initialize other defaults. */ |
641 | 1.09M | plfont->orient = 0; |
642 | 1.09M | plfont->allow_vertical_substitutes = false; |
643 | 1.09M | plfont->bold_fraction = 0; |
644 | 1.09M | plfont->font_file = 0; |
645 | 1.09M | plfont->resolution.x = plfont->resolution.y = 0; |
646 | 1.09M | plfont->params.proportional_spacing = true; |
647 | 1.09M | memset(plfont->character_complement, 0xff, 8); |
648 | 1.09M | plfont->offsets.GC = plfont->offsets.GT = plfont->offsets.VT = -1; |
649 | 1.09M | plfont->pts_per_inch = 72.0; /* normal value */ |
650 | 1.09M | plfont->widths_cache = NULL; |
651 | 1.09M | plfont->widths_cache_nitems = 0; |
652 | 1.09M | plfont->names = NULL; |
653 | 1.09M | plfont->max_name_index = 0; |
654 | 1.09M | plfont->next_name_index = 0; |
655 | 1.09M | } |
656 | 1.09M | return plfont; |
657 | 1.09M | } |
658 | | |
659 | | /* Structure descriptors for cloning fonts */ |
660 | | gs_private_st_ptrs1(st_pl_font_glyph_f, pl_font_glyph_t, "pl_font_glyph_t", |
661 | | pl_font_glyph_enum_ptrs_f, pl_font_glyph_reloc_ptrs_f, |
662 | | data); |
663 | | gs_private_st_element(st_pl_font_glyph_element_f, pl_font_glyph_t, |
664 | | "pl_font_glyph_t[]", pl_font_glyph_elt_enum_ptrs_f, |
665 | | pl_font_glyph_elt_reloc_ptrs_f, st_pl_font_glyph_f); |
666 | | |
667 | | pl_font_t * |
668 | | pl_clone_font(const pl_font_t * src, gs_memory_t * mem, client_name_t cname) |
669 | 0 | { |
670 | 0 | pl_font_t *plfont = gs_alloc_struct(mem, pl_font_t, &st_pl_font, cname); |
671 | |
|
672 | 0 | if (plfont == 0) |
673 | 0 | return 0; |
674 | | /* copy technology common parts */ |
675 | 0 | plfont->storage = src->storage; |
676 | 0 | plfont->header_size = src->header_size; |
677 | 0 | plfont->scaling_technology = src->scaling_technology; |
678 | 0 | plfont->is_xl_format = src->is_xl_format; |
679 | 0 | plfont->allow_vertical_substitutes = src->allow_vertical_substitutes; |
680 | 0 | plfont->font_type = src->font_type; |
681 | 0 | plfont->char_width = src->char_width; |
682 | 0 | plfont->char_metrics = src->char_metrics; |
683 | 0 | plfont->large_sizes = src->large_sizes; |
684 | 0 | plfont->resolution = src->resolution; |
685 | 0 | plfont->params = src->params; |
686 | 0 | plfont->pts_per_inch = src->pts_per_inch; |
687 | 0 | plfont->font_file_loaded = src->font_file_loaded; |
688 | 0 | plfont->orient = src->orient; |
689 | 0 | plfont->bold_fraction = src->bold_fraction; |
690 | 0 | plfont->widths_cache = NULL; |
691 | 0 | plfont->widths_cache_nitems = 0; |
692 | 0 | { |
693 | 0 | int i; |
694 | |
|
695 | 0 | for (i = 0; i < sizeof(src->character_complement); i++) |
696 | 0 | plfont->character_complement[i] = src->character_complement[i]; |
697 | 0 | } |
698 | 0 | plfont->offsets = src->offsets; |
699 | 0 | plfont->header = gs_alloc_bytes(mem, src->header_size, cname); |
700 | 0 | if (plfont->header == 0) |
701 | 0 | return 0; |
702 | 0 | memcpy(plfont->header, src->header, src->header_size); |
703 | |
|
704 | 0 | plfont->names = NULL; |
705 | 0 | plfont->max_name_index = 0; |
706 | 0 | plfont->next_name_index = 0; |
707 | |
|
708 | 0 | if (src->font_file) { |
709 | 0 | plfont->font_file = |
710 | 0 | (char *)gs_alloc_bytes(mem, strlen(src->font_file) + 1, |
711 | 0 | "pl_clone_font"); |
712 | 0 | if (plfont->font_file == 0) |
713 | 0 | return 0; /* #NB errors!!! */ |
714 | 0 | strcpy(plfont->font_file, src->font_file); |
715 | 0 | } else |
716 | 0 | plfont->font_file = 0; |
717 | | /* technology specific setup */ |
718 | 0 | switch (plfont->scaling_technology) { |
719 | 0 | case plfst_bitmap: |
720 | 0 | { |
721 | 0 | gs_font_base *pfont = |
722 | 0 | gs_alloc_struct(mem, gs_font_base, &st_gs_font_base, |
723 | 0 | cname); |
724 | 0 | if (pfont == 0) |
725 | 0 | return 0; |
726 | 0 | pl_fill_in_font((gs_font *) pfont, plfont, src->pfont->dir, |
727 | 0 | mem, "nameless_font"); |
728 | 0 | pl_fill_in_bitmap_font(pfont, gs_next_ids(mem, 1)); |
729 | 0 | break; |
730 | 0 | } |
731 | 0 | case plfst_Intellifont: |
732 | 0 | { |
733 | 0 | gs_font_base *pfont = |
734 | 0 | gs_alloc_struct(mem, gs_font_base, &st_gs_font_base, |
735 | 0 | cname); |
736 | 0 | if (pfont == 0) |
737 | 0 | return 0; |
738 | 0 | pl_fill_in_font((gs_font *) pfont, plfont, src->pfont->dir, |
739 | 0 | mem, "nameless_font"); |
740 | 0 | pl_fill_in_intelli_font(pfont, gs_next_ids(mem, 1)); |
741 | 0 | break; |
742 | 0 | } |
743 | 0 | case plfst_TrueType: |
744 | 0 | { |
745 | 0 | { |
746 | 0 | gs_font_type42 *pfont = |
747 | 0 | gs_alloc_struct(mem, gs_font_type42, |
748 | 0 | &st_gs_font_type42, cname); |
749 | | /* detect if a truetype font is downloaded or |
750 | | internal. There must be a better way... */ |
751 | 0 | gs_font_type42 *pfont_src = (gs_font_type42 *) src->pfont; |
752 | 0 | bool downloaded = |
753 | 0 | (pfont_src->data.get_outline == pl_tt_get_outline); |
754 | 0 | if (pfont == 0) |
755 | 0 | return 0; |
756 | 0 | pl_fill_in_font((gs_font *) pfont, plfont, |
757 | 0 | src->pfont->dir, mem, "nameless_font"); |
758 | 0 | pl_fill_in_tt_font(pfont, downloaded ? NULL : src->header, |
759 | 0 | gs_next_ids(mem, 1)); |
760 | 0 | } |
761 | 0 | break; |
762 | 0 | } |
763 | 0 | default: |
764 | 0 | return 0; |
765 | 0 | } |
766 | 0 | if (src->char_glyphs.table != 0) { |
767 | | /* HAS may gs_alloc_struct_array() here but this is |
768 | | consistant with pl_tt_alloc_char_glyphs() */ |
769 | 0 | pl_tt_char_glyph_t *char_glyphs = |
770 | 0 | (pl_tt_char_glyph_t *) gs_alloc_byte_array(mem, |
771 | 0 | src->char_glyphs.size, |
772 | 0 | sizeof |
773 | 0 | (pl_tt_char_glyph_t), |
774 | 0 | cname); |
775 | 0 | int i; |
776 | |
|
777 | 0 | if (char_glyphs == 0) |
778 | 0 | return 0; |
779 | 0 | for (i = 0; i < src->char_glyphs.size; i++) |
780 | 0 | char_glyphs[i] = src->char_glyphs.table[i]; |
781 | | /* once again a copy struct shortcut and then are restore |
782 | | of the char_glyphs.table pointer */ |
783 | 0 | plfont->char_glyphs = src->char_glyphs; |
784 | 0 | plfont->char_glyphs.table = char_glyphs; |
785 | 0 | } else /* no character glyph table data */ |
786 | 0 | plfont->char_glyphs = src->char_glyphs; |
787 | | |
788 | 0 | if (src->glyphs.table != 0) { |
789 | 0 | int i; |
790 | |
|
791 | 0 | plfont->glyphs.table = |
792 | 0 | gs_alloc_struct_array(mem, src->glyphs.size, pl_font_glyph_t, |
793 | 0 | &st_pl_font_glyph_element_f, cname); |
794 | 0 | if (plfont->glyphs.table == NULL) |
795 | 0 | return 0; |
796 | 0 | plfont->glyphs.used = src->glyphs.used; |
797 | 0 | plfont->glyphs.limit = src->glyphs.limit; |
798 | 0 | plfont->glyphs.size = src->glyphs.size; |
799 | 0 | plfont->glyphs.skip = src->glyphs.skip; |
800 | 0 | for (i = 0; i < src->glyphs.size; i++) { |
801 | 0 | const byte *data = src->glyphs.table[i].data; |
802 | 0 | byte *char_data; |
803 | |
|
804 | 0 | plfont->glyphs.table[i].glyph = src->glyphs.table[i].glyph; |
805 | 0 | plfont->glyphs.table[i].data = 0; |
806 | 0 | if (data) { |
807 | 0 | uint size = src->glyphs.table[i].data_len; |
808 | 0 | char_data = gs_alloc_bytes(mem, size, cname); |
809 | 0 | if (char_data == 0) |
810 | 0 | return 0; |
811 | 0 | memcpy(char_data, data, size); |
812 | 0 | plfont->glyphs.table[i].data = char_data; |
813 | 0 | plfont->glyphs.table[i].data_len = size; |
814 | 0 | } |
815 | |
|
816 | 0 | } |
817 | 0 | } else /* no glyph table */ |
818 | 0 | plfont->glyphs = src->glyphs; |
819 | 0 | return plfont; |
820 | 0 | } |
821 | | |
822 | | /* Fill in generic font boilerplate. NB TODO examine duplication with |
823 | | gs_font_alloc(). The font name must not contain spaces. It is |
824 | | used for PDF output and Acrobat (some versions) do not process the |
825 | | file correctly with spaces in the name. */ |
826 | | int |
827 | | pl_fill_in_font(gs_font * pfont, pl_font_t * plfont, gs_font_dir * pdir, |
828 | | gs_memory_t * mem, const char *font_name) |
829 | 1.14M | { |
830 | 1.14M | gs_font_base *pbfont = (gs_font_base *) pfont; |
831 | | |
832 | 1.14M | plfont->pfont = pfont; |
833 | | /* Initialize generic font data. */ |
834 | 1.14M | gs_make_identity(&pbfont->orig_FontMatrix); |
835 | 1.14M | gs_make_identity(&pbfont->FontMatrix); |
836 | 1.14M | pbfont->next = pbfont->prev = 0; |
837 | 1.14M | pbfont->memory = mem; |
838 | 1.14M | pbfont->dir = pdir; |
839 | 1.14M | pbfont->is_resource = false; |
840 | 1.14M | gs_notify_init(&pbfont->notify_list, gs_memory_stable(mem)); |
841 | 1.14M | pbfont->base = (gs_font *) pbfont; |
842 | 1.14M | pbfont->client_data = plfont; |
843 | 1.14M | pbfont->WMode = 0; |
844 | 1.14M | pbfont->PaintType = 0; |
845 | 1.14M | pbfont->StrokeWidth = 0; |
846 | 1.14M | pbfont->is_cached = 0; |
847 | 1.14M | pbfont->procs.init_fstack = gs_default_init_fstack; |
848 | 1.14M | pbfont->procs.next_char_glyph = gs_default_next_char_glyph; |
849 | 1.14M | pbfont->FAPI = NULL; |
850 | 1.14M | pbfont->FAPI_font_data = NULL; |
851 | | |
852 | 1.14M | pbfont->procs.glyph_name = pl_glyph_name; |
853 | 1.14M | pbfont->procs.decode_glyph = pl_decode_glyph; |
854 | | /* NB pbfont->procs.callbacks.known_encode = pl_known_encode; */ |
855 | 1.14M | pbfont->procs.define_font = gs_no_define_font; |
856 | 1.14M | pbfont->procs.make_font = gs_no_make_font; |
857 | 1.14M | pbfont->procs.font_info = gs_default_font_info; |
858 | 1.14M | pbfont->procs.glyph_info = gs_default_glyph_info; |
859 | 1.14M | pbfont->procs.glyph_outline = gs_no_glyph_outline; |
860 | 1.14M | pbfont->id = gs_next_ids(mem, 1); |
861 | 1.14M | { |
862 | 1.14M | size_t sz = strlen(font_name); |
863 | 1.14M | gs_font_name *fnm = &pbfont->font_name; |
864 | 1.14M | gs_font_name *knm = &pbfont->key_name; |
865 | | |
866 | 1.14M | if (sz > gs_font_name_max) |
867 | 0 | sz = gs_font_name_max; |
868 | 1.14M | fnm->size = knm->size = sz; |
869 | | |
870 | 1.14M | memcpy(fnm->chars, font_name, sz); |
871 | 1.14M | fnm->chars[sz] = 0; |
872 | | |
873 | 1.14M | memcpy(knm->chars, font_name, sz); |
874 | 1.14M | knm->chars[sz] = 0; |
875 | 1.14M | } |
876 | 1.14M | return 0; |
877 | 1.14M | } |
878 | | |
879 | | /* Fill in bitmap font boilerplate. */ |
880 | | void |
881 | | pl_fill_in_bitmap_font(gs_font_base * pfont, long unique_id) |
882 | 12.3k | { |
883 | 12.3k | pfont->FontType = ft_PCL_user_defined; |
884 | 12.3k | pfont->BitmapWidths = true; |
885 | 12.3k | pfont->ExactSize = fbit_use_bitmaps; |
886 | 12.3k | pfont->InBetweenSize = fbit_use_bitmaps; |
887 | 12.3k | pfont->TransformedChar = fbit_transform_bitmaps; |
888 | 12.3k | pl_bitmap_init_procs(pfont); |
889 | | /* We have no idea what the FontBBox should be. */ |
890 | 12.3k | pfont->FontBBox.p.x = pfont->FontBBox.p.y = |
891 | 12.3k | pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0; |
892 | 12.3k | uid_set_UniqueID(&pfont->UID, unique_id); |
893 | 12.3k | pfont->encoding_index = 1; /****** WRONG ******/ |
894 | 12.3k | pfont->nearest_encoding_index = 1; /****** WRONG ******/ |
895 | 12.3k | } |
896 | | |
897 | | /* Fill in TrueType font boilerplate. */ |
898 | | int |
899 | | pl_fill_in_tt_font(gs_font_type42 * pfont, void *data, long unique_id) |
900 | 1.08M | { |
901 | 1.08M | pfont->FontType = ft_TrueType; |
902 | 1.08M | pfont->BitmapWidths = true; |
903 | 1.08M | pfont->ExactSize = fbit_use_outlines; |
904 | 1.08M | pfont->InBetweenSize = fbit_use_outlines; |
905 | 1.08M | pfont->TransformedChar = fbit_use_outlines; |
906 | | /* Initialize base font data. */ |
907 | | /* |
908 | | * We can't set the FontBBox correctly until we've initialized the |
909 | | * Type 42 specific data, but we need to set it to an empty box now |
910 | | * for the sake of gs_type42_font_init. |
911 | | */ |
912 | 1.08M | pfont->FontBBox.p.x = pfont->FontBBox.p.y = |
913 | 1.08M | pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0; |
914 | 1.08M | uid_set_UniqueID(&pfont->UID, unique_id); |
915 | 1.08M | pfont->encoding_index = 1; /****** WRONG ******/ |
916 | 1.08M | pfont->nearest_encoding_index = 1; /****** WRONG ******/ |
917 | | /* Initialize Type 42 specific data. */ |
918 | 1.08M | pfont->data.proc_data = data; |
919 | 1.08M | pl_tt_init_procs(pfont); |
920 | 1.08M | { |
921 | 1.08M | int code = gs_type42_font_init(pfont, 0); |
922 | | |
923 | 1.08M | if (code < 0) |
924 | 3 | return code; |
925 | 1.08M | } |
926 | | /* disable unused FAPI */ |
927 | 1.08M | pfont->FAPI = 0; |
928 | 1.08M | pfont->FAPI_font_data = 0; |
929 | 1.08M | pl_tt_finish_init(pfont, !data); |
930 | 1.08M | return 0; |
931 | 1.08M | } |
932 | | |
933 | | /* Fill in Intellifont boilerplate. */ |
934 | | void |
935 | | pl_fill_in_intelli_font(gs_font_base * pfont, long unique_id) |
936 | 0 | { /* Intellifonts have an 8782-unit design space. */ |
937 | 0 | { |
938 | 0 | gs_matrix mat; |
939 | |
|
940 | 0 | gs_make_scaling(1.0 / 8782, 1.0 / 8782, &mat); |
941 | 0 | gs_matrix_translate(&mat, -2980.0, -5380.0, &pfont->orig_FontMatrix); |
942 | 0 | } |
943 | 0 | pfont->FontType = ft_MicroType; |
944 | 0 | pfont->BitmapWidths = true; |
945 | 0 | pfont->ExactSize = fbit_use_outlines; |
946 | 0 | pfont->InBetweenSize = fbit_use_outlines; |
947 | 0 | pfont->TransformedChar = fbit_use_outlines; |
948 | | /* We have no idea what the FontBBox should be. */ |
949 | 0 | pfont->FontBBox.p.x = pfont->FontBBox.p.y = |
950 | 0 | pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0; |
951 | 0 | uid_set_UniqueID(&pfont->UID, unique_id); |
952 | 0 | pfont->encoding_index = 1; /****** WRONG ******/ |
953 | 0 | pfont->nearest_encoding_index = 1; /****** WRONG ******/ |
954 | 0 | pl_intelli_init_procs(pfont); |
955 | 0 | } |
956 | | |
957 | | /* |
958 | | * Set large_sizes, scaling_technology, character_complement, offsets |
959 | | * (for TrueType fonts), and resolution (for bitmap fonts) by scanning |
960 | | * the segments of a segmented downloaded font. |
961 | | * This is used for PCL5 Format 15 and 16 fonts and for PCL XL fonts. |
962 | | * fst_offset is the offset of the Font Scaling Technology and Variety bytes; |
963 | | * the segment data runs from start_offset up to end_offset. |
964 | | * large_sizes = false indicates 2-byte segment sizes, true indicates 4-byte. |
965 | | */ |
966 | | int |
967 | | pl_font_scan_segments(const gs_memory_t * mem, |
968 | | pl_font_t * plfont, int fst_offset, int start_offset, |
969 | | long end_offset, bool large_sizes, |
970 | | const pl_font_offset_errors_t * pfoe) |
971 | 12.2k | { |
972 | 12.2k | const byte *header = plfont->header; |
973 | 12.2k | pl_font_scaling_technology_t fst = header[fst_offset]; |
974 | 12.2k | int wsize = (large_sizes ? 4 : 2); |
975 | 12.2k | const byte *segment = header + start_offset; |
976 | 12.2k | const byte *end = header + end_offset; |
977 | 12.2k | const byte *null_segment = end - (2 + wsize); |
978 | 12.2k | bool found = false; |
979 | 12.2k | ulong seg_size; |
980 | 12.2k | int illegal_font_data = pfoe->illegal_font_data; |
981 | | |
982 | 12.2k | #define return_scan_error(err)\ |
983 | 12.2k | return_error((err) ? (err) : illegal_font_data); |
984 | | |
985 | 12.2k | if (memcmp(null_segment, "\377\377", 2) /* NULL segment header */ ) |
986 | 12.2k | return_scan_error(pfoe->missing_required_segment); |
987 | 12.2k | if (memcmp(null_segment + 2, "\0\0\0\0", wsize) /* NULL segment size */ ) |
988 | 12.2k | return_scan_error(pfoe->illegal_null_segment_size); |
989 | 12.2k | switch (fst) { |
990 | 12.2k | case plfst_bitmap: |
991 | 12.2k | case plfst_TrueType: |
992 | 12.2k | break; |
993 | 0 | default: |
994 | 0 | return_scan_error(pfoe->illegal_font_header_fields); |
995 | 12.2k | } |
996 | 12.2k | if (header[fst_offset + 1]) /* variety, must be 0 */ |
997 | 12.2k | return_scan_error(pfoe->illegal_font_header_fields); |
998 | | /* Scan the segments. */ |
999 | 36.7k | for (; end - segment >= 2 + wsize; segment += 2 + wsize + seg_size) { |
1000 | 24.5k | uint seg_id = u16(segment); |
1001 | 24.5k | const byte *sdata = segment + 2 + wsize; |
1002 | | |
1003 | 24.5k | #define id2(c1,c2) (((uint)(c1) << 8) + (c2)) |
1004 | | |
1005 | 24.5k | seg_size = (large_sizes ? u32(segment + 2) : u16(segment + 2)); |
1006 | 24.5k | if (seg_size + 2 + wsize > end - segment) |
1007 | 1 | return_error(illegal_font_data); |
1008 | | /* Handle segments common to all fonts. */ |
1009 | 24.5k | switch (seg_id) { |
1010 | 12.2k | case 0xffff: /* NULL segment ID */ |
1011 | 12.2k | if (segment != null_segment) |
1012 | 0 | return_error(illegal_font_data); |
1013 | 12.2k | continue; |
1014 | 12.2k | case id2('V', 'I'): |
1015 | 0 | continue; |
1016 | 0 | case id2('C', 'C'): |
1017 | 0 | if (seg_size != 8) |
1018 | 0 | return_error(illegal_font_data); |
1019 | 0 | memcpy(plfont->character_complement, sdata, 8); |
1020 | 0 | continue; |
1021 | 12.2k | default: |
1022 | 12.2k | ; |
1023 | 24.5k | } |
1024 | | /* Handle segments specific to the scaling technology. */ |
1025 | 12.2k | if (fst == plfst_bitmap) |
1026 | 12.2k | switch (seg_id) { |
1027 | 12.2k | case id2('B', 'R'): |
1028 | 12.2k | if (seg_size != 4) |
1029 | 12.2k | return_scan_error(pfoe->illegal_BR_segment); |
1030 | 12.2k | { |
1031 | 12.2k | uint xres = pl_get_uint16(sdata); |
1032 | 12.2k | uint yres = pl_get_uint16(sdata + 2); |
1033 | | |
1034 | 12.2k | if (xres == 0 || yres == 0) |
1035 | 12.2k | return_scan_error(pfoe->illegal_BR_segment); |
1036 | 12.2k | plfont->resolution.x = xres; |
1037 | 12.2k | plfont->resolution.y = yres; |
1038 | 12.2k | } |
1039 | 12.2k | found = true; |
1040 | 12.2k | break; |
1041 | 1 | default: |
1042 | 1 | if (pfoe->illegal_font_segment < 0) |
1043 | 1 | return_error(pfoe->illegal_font_segment); |
1044 | 12.2k | } else /* fst == plfst_TrueType */ |
1045 | 62 | switch (seg_id) { |
1046 | 62 | case id2('G', 'T'): |
1047 | | /* |
1048 | | * We don't do much checking here, but we do check that |
1049 | | * the segment starts with a table directory that |
1050 | | * includes at least 3 elements (gdir, head, |
1051 | | * maxp -- but we don't check the actual names). |
1052 | | */ |
1053 | 62 | if (seg_size < 12 + 5 * 16 || |
1054 | | /* memcmp(sdata, "\000\001\000\000", 4) || */ |
1055 | 62 | u16(sdata + 4) < 3) |
1056 | 62 | return_scan_error(pfoe->illegal_GT_segment); |
1057 | 62 | plfont->offsets.GT = segment - header; |
1058 | 62 | found = true; |
1059 | 62 | break; |
1060 | 0 | case id2('G', 'C'): |
1061 | 0 | if (seg_size < 6 || u16(sdata) != 0 || |
1062 | 0 | seg_size != u16(sdata + 4) * 6 + 6) |
1063 | 0 | return_scan_error(pfoe->illegal_GC_segment); |
1064 | 0 | plfont->offsets.GC = segment - header; |
1065 | 0 | break; |
1066 | 0 | case id2('V', 'T'): |
1067 | | /* Check for end of table mark */ |
1068 | 0 | if ((seg_size & 3) != 0 || seg_size < 4 || |
1069 | 0 | u16(sdata + seg_size - 4) != 0xffff) |
1070 | 0 | return_scan_error(pfoe->illegal_VT_segment); |
1071 | | /* Check for table sorted by horizontal glyph ID */ |
1072 | 0 | { |
1073 | 0 | uint i; |
1074 | |
|
1075 | 0 | for (i = 0; i < seg_size - 4; i += 4) |
1076 | 0 | if (u16(sdata + i) > u16(sdata + i + 4)) |
1077 | 0 | return_scan_error(pfoe->illegal_VT_segment); |
1078 | 0 | } |
1079 | 0 | plfont->offsets.VT = segment - header; |
1080 | 0 | break; |
1081 | 0 | case id2('V', 'E'): /* nb unimplemented */ |
1082 | 0 | break; |
1083 | 0 | case id2('V', 'R'): /* nb unimplemented */ |
1084 | 0 | break; |
1085 | 0 | case id2('C', 'E'): /* nb unimplemented */ |
1086 | 0 | break; |
1087 | 0 | default: |
1088 | 0 | if (pfoe->illegal_font_segment < 0) |
1089 | 0 | return_error(pfoe->illegal_font_segment); |
1090 | 62 | } |
1091 | 12.2k | #undef id2 |
1092 | 12.2k | } |
1093 | 12.2k | if (!found) |
1094 | 12.2k | return_scan_error(pfoe->missing_required_segment); |
1095 | 12.2k | if (segment != end) |
1096 | 0 | return_error(illegal_font_data); |
1097 | 12.2k | plfont->large_sizes = large_sizes; |
1098 | 12.2k | plfont->scaling_technology = fst; |
1099 | 12.2k | return 0; |
1100 | 12.2k | #undef return_scan_error |
1101 | 12.2k | } |
1102 | | |
1103 | | int |
1104 | | pl_free_tt_fontfile_buffer(gs_memory_t * mem, byte * ptt_font_data) |
1105 | 0 | { |
1106 | 0 | gs_free_object(mem, ptt_font_data, "pl_tt_load_font data"); |
1107 | 0 | return 0; |
1108 | 0 | } |
1109 | | |
1110 | | int |
1111 | | pl_alloc_tt_fontfile_buffer(stream * in, gs_memory_t * mem, |
1112 | | byte ** pptt_font_data, ulong * size) |
1113 | 1.08M | { |
1114 | 1.08M | ulong len = (sfseek(in, 0L, SEEK_END), sftell(in)); |
1115 | | |
1116 | 1.08M | *size = 6 + len; /* leave room for segment header */ |
1117 | 1.08M | if (*size != (uint) (*size)) { |
1118 | | /* |
1119 | | * The font is too big to load in a single piece -- punt. |
1120 | | * The error message is bogus, but there isn't any more |
1121 | | * appropriate one. |
1122 | | */ |
1123 | 0 | sfclose(in); |
1124 | 0 | return_error(gs_error_VMerror); |
1125 | 0 | } |
1126 | 1.08M | srewind(in); |
1127 | 1.08M | *pptt_font_data = gs_alloc_bytes(mem, *size, "pl_tt_load_font data"); |
1128 | 1.08M | if (*pptt_font_data == 0) { |
1129 | 0 | sfclose(in); |
1130 | 0 | return_error(gs_error_VMerror); |
1131 | 0 | } |
1132 | 1.08M | sfread(*pptt_font_data + 6, 1, len, in); |
1133 | 1.08M | sfclose(in); |
1134 | 1.08M | return 0; |
1135 | 1.08M | } |
1136 | | |
1137 | | /* Load a built-in (TrueType) font from external storage. */ |
1138 | | int |
1139 | | pl_load_tt_font(stream * in, gs_font_dir * pdir, gs_memory_t * mem, |
1140 | | long unique_id, pl_font_t ** pplfont, char *font_name) |
1141 | 1.08M | { |
1142 | 1.08M | byte *tt_font_datap = NULL; |
1143 | 1.08M | ulong size; |
1144 | 1.08M | int code; |
1145 | 1.08M | gs_font_type42 *pfont = NULL; |
1146 | 1.08M | pl_font_t *plfont = NULL; |
1147 | 1.08M | byte *file_name = NULL; |
1148 | 1.08M | gs_const_string pfname; |
1149 | | |
1150 | 1.08M | if (sfilename(in, &pfname) == 0) { |
1151 | 1.08M | file_name = |
1152 | 1.08M | gs_alloc_bytes(mem, pfname.size + 1, "pl_load_tt_font file_name"); |
1153 | 1.08M | if (!file_name) { |
1154 | 0 | sfclose(in); |
1155 | 0 | return_error(gs_error_VMerror); |
1156 | 0 | } |
1157 | | /* the stream code guarantees the string is null terminated */ |
1158 | 1.08M | memcpy(file_name, pfname.data, pfname.size + 1); |
1159 | 1.08M | } |
1160 | | |
1161 | | /* get the data from the file */ |
1162 | 1.08M | code = pl_alloc_tt_fontfile_buffer(in, mem, &tt_font_datap, &size); |
1163 | 1.08M | if (code < 0) |
1164 | 0 | goto error; |
1165 | | /* Make a Type 42 font out of the TrueType data. */ |
1166 | 1.08M | pfont = gs_alloc_struct(mem, gs_font_type42, &st_gs_font_type42, |
1167 | 1.08M | "pl_tt_load_font(gs_font_type42)"); |
1168 | 1.08M | if (pfont == NULL) { |
1169 | 0 | code = gs_error_VMerror; |
1170 | 0 | goto error; |
1171 | 0 | } |
1172 | 1.08M | memset(pfont, 0, sizeof(*pfont)); |
1173 | 1.08M | plfont = pl_alloc_font(mem, "pl_tt_load_font(pl_font_t)"); |
1174 | 1.08M | if (plfont == NULL) { |
1175 | 0 | code = gs_error_VMerror; |
1176 | 0 | goto error; |
1177 | 0 | } |
1178 | | |
1179 | | /* Initialize general font boilerplate. */ |
1180 | 1.08M | code = pl_fill_in_font((gs_font *) pfont, plfont, pdir, mem, font_name); |
1181 | 1.08M | if (code < 0) |
1182 | 0 | goto error; |
1183 | | |
1184 | | /* Initialize TrueType font boilerplate. */ |
1185 | 1.08M | plfont->header = tt_font_datap; |
1186 | 1.08M | plfont->header_size = size; |
1187 | 1.08M | plfont->scaling_technology = plfst_TrueType; |
1188 | 1.08M | plfont->font_type = plft_Unicode; |
1189 | 1.08M | plfont->large_sizes = true; |
1190 | 1.08M | plfont->offsets.GT = 0; |
1191 | 1.08M | plfont->is_xl_format = false; |
1192 | 1.08M | code = pl_fill_in_tt_font(pfont, tt_font_datap, unique_id); |
1193 | 1.08M | if (code < 0) |
1194 | 0 | goto error; |
1195 | 1.08M | code = gs_definefont(pdir, (gs_font *) pfont); |
1196 | 1.08M | if (code < 0) |
1197 | 0 | goto error; |
1198 | | |
1199 | 1.08M | code = pl_fapi_passfont(plfont, 0, NULL, (char *)file_name, NULL, 0); |
1200 | 1.08M | if (code < 0) |
1201 | 0 | goto error; |
1202 | 1.08M | if (file_name) |
1203 | 1.08M | gs_free_object(mem, file_name, "pl_load_tt_font file_name"); |
1204 | | |
1205 | 1.08M | *pplfont = plfont; |
1206 | 1.08M | return 0; |
1207 | | |
1208 | 0 | error: |
1209 | 0 | gs_free_object(mem, plfont, "pl_tt_load_font(pl_font_t)"); |
1210 | 0 | gs_free_object(mem, pfont, "pl_tt_load_font(gs_font_type42)"); |
1211 | 0 | pl_free_tt_fontfile_buffer(mem, tt_font_datap); |
1212 | 0 | gs_free_object(mem, file_name, "pl_load_tt_font file_name"); |
1213 | 0 | return_error(code); |
1214 | 1.08M | } |
1215 | | |
1216 | | /* load resident font data to ram */ |
1217 | | int |
1218 | | pl_load_resident_font_data_from_file(gs_memory_t * mem, pl_font_t * plfont) |
1219 | 621k | { |
1220 | | |
1221 | 621k | ulong len, size; |
1222 | 621k | byte *data; |
1223 | | |
1224 | 621k | if (plfont->font_file && !plfont->font_file_loaded) { |
1225 | 34.7k | stream *in = sfopen(plfont->font_file, "r", mem); |
1226 | | |
1227 | 34.7k | if (in == NULL) |
1228 | 0 | return -1; |
1229 | | /* note this is exactly the same as the code in pl_load_tt_font */ |
1230 | 34.7k | len = (sfseek(in, 0L, SEEK_END), sftell(in)); |
1231 | 34.7k | size = 6 + len; /* leave room for segment header */ |
1232 | | |
1233 | 34.7k | if (size != (uint) size) { |
1234 | | /* |
1235 | | * The font is too big to load in a single piece -- punt. |
1236 | | * The error message is bogus, but there isn't any more |
1237 | | * appropriate one. |
1238 | | */ |
1239 | 0 | sfclose(in); |
1240 | 0 | return_error(gs_error_VMerror); |
1241 | 0 | } |
1242 | 34.7k | srewind(in); |
1243 | 34.7k | data = gs_alloc_bytes(mem, size, "pl_tt_load_font data"); |
1244 | 34.7k | if (data == 0) { |
1245 | 0 | sfclose(in); |
1246 | 0 | return_error(gs_error_VMerror); |
1247 | 0 | } |
1248 | 34.7k | sfread(data + 6, 1, len, in); |
1249 | 34.7k | sfclose(in); |
1250 | 34.7k | plfont->header = data; |
1251 | 34.7k | plfont->header_size = size; |
1252 | 34.7k | plfont->font_file_loaded = true; |
1253 | 34.7k | } |
1254 | 621k | return 0; |
1255 | 621k | } |
1256 | | |
1257 | | /* Keep resident font data in (header) and deallocate the memory */ |
1258 | | int |
1259 | | pl_store_resident_font_data_in_file(char *font_file, gs_memory_t * mem, |
1260 | | pl_font_t * plfont) |
1261 | 825k | { |
1262 | | /* Free the header data */ |
1263 | 825k | if (plfont->header) { |
1264 | 825k | gs_free_object(mem, plfont->header, |
1265 | 825k | "pl_store_resident_font_data_in_file"); |
1266 | 825k | plfont->header = 0; |
1267 | 825k | plfont->header_size = 0; |
1268 | 825k | } else { |
1269 | | /* nothing to do */ |
1270 | 0 | return 0; |
1271 | 0 | } |
1272 | | /* we don't yet have a filename for this font object. create one |
1273 | | and store it in the font. */ |
1274 | 825k | if (!plfont->font_file) { |
1275 | 825k | plfont->font_file = |
1276 | 825k | (char *)gs_alloc_bytes(mem, strlen(font_file) + 1, |
1277 | 825k | "pl_store_resident_font_data_in_file"); |
1278 | 825k | if (plfont->font_file == 0) |
1279 | 0 | return -1; |
1280 | 825k | strcpy(plfont->font_file, font_file); |
1281 | 825k | } |
1282 | | /* designate that the font data is not in RAM */ |
1283 | 825k | plfont->font_file_loaded = false; |
1284 | 825k | return 0; |
1285 | 825k | } |
1286 | | |
1287 | | pl_font_t * |
1288 | | pl_lookup_font_by_pjl_number(pl_dict_t * pfontdict, int pjl_font_number) |
1289 | 66.0k | { |
1290 | 66.0k | pl_dict_enum_t dictp; |
1291 | 66.0k | gs_const_string key; |
1292 | 66.0k | void *value; |
1293 | | |
1294 | 66.0k | pl_dict_enum_begin(pfontdict, &dictp); |
1295 | 3.40M | while (pl_dict_enum_next(&dictp, &key, &value)) { |
1296 | 3.40M | pl_font_t *plfont = value; |
1297 | | |
1298 | 3.40M | if (plfont->params.pjl_font_number == pjl_font_number) |
1299 | 66.0k | return value; |
1300 | 3.40M | } |
1301 | 0 | return (pl_font_t *) NULL; |
1302 | 66.0k | } |