1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gsfont.c,v 1.37 2005/07/27 11:24:38 igor Exp $ */
18 /* Font operators for Ghostscript library */
19 #include "gx.h"
20 #include "memory_.h"
21 #include "gserrors.h"
22 #include "gsstruct.h"
23 #include "gsutil.h"
24 #include "gxfixed.h"
25 #include "gxmatrix.h"
26 #include "gzstate.h" /* must precede gxdevice */
27 #include "gxdevice.h" /* must precede gxfont */
28 #include "gxfont.h"
29 #include "gxfcache.h"
30 #include "gzpath.h" /* for default implementation */
31
32 /* Define the sizes of the various aspects of the font/character cache. */
33 /*** Big memory machines ***/
34 #define smax_LARGE 50 /* smax - # of scaled fonts */
35 #define bmax_LARGE 500000 /* bmax - space for cached chars */
36 #define mmax_LARGE 200 /* mmax - # of cached font/matrix pairs */
37 #define cmax_LARGE 5000 /* cmax - # of cached chars */
38 #define blimit_LARGE 2500 /* blimit/upper - max size of a single cached char */
39 /*** Small memory machines ***/
40 #define smax_SMALL 20 /* smax - # of scaled fonts */
41 #define bmax_SMALL 25000 /* bmax - space for cached chars */
42 #define mmax_SMALL 40 /* mmax - # of cached font/matrix pairs */
43 #define cmax_SMALL 500 /* cmax - # of cached chars */
44 #define blimit_SMALL 100 /* blimit/upper - max size of a single cached char */
45
46 /* Define a default procedure vector for fonts. */
47 const gs_font_procs gs_font_procs_default = {
48 gs_no_define_font, /* (actually a default) */
49 gs_no_make_font, /* (actually a default) */
50 gs_default_font_info,
51 gs_default_same_font,
52 gs_no_encode_char,
53 gs_no_decode_glyph,
54 gs_no_enumerate_glyph,
55 gs_default_glyph_info,
56 gs_no_glyph_outline,
57 gs_no_glyph_name,
58 gs_default_init_fstack,
59 gs_default_next_char_glyph,
60 gs_no_build_char
61 };
62
63 private_st_font_dir();
64 private struct_proc_enum_ptrs(font_enum_ptrs);
65 private struct_proc_reloc_ptrs(font_reloc_ptrs);
66
67 public_st_gs_font_info();
68 public_st_gs_font();
69 public_st_gs_font_base();
70 private_st_gs_font_ptr();
71 public_st_gs_font_ptr_element();
72
73 /*
74 * Garbage collection of fonts poses some special problems. On the one
75 * hand, we need to keep track of all existing base (not scaled) fonts,
76 * using the next/prev list whose head is the orig_fonts member of the font
77 * directory; on the other hand, we want these to be "weak" pointers that
78 * don't keep fonts in existence if the fonts aren't referenced from
79 * anywhere else. We accomplish this as follows:
80 *
81 * We don't trace through gs_font_dir.orig_fonts or gs_font.{next,prev}
82 * during the mark phase of the GC.
83 *
84 * When we finalize a base gs_font, we unlink it from the list. (A
85 * gs_font is a base font iff its base member points to itself.)
86 *
87 * We *do* relocate the orig_fonts and next/prev pointers during the
88 * relocation phase of the GC. */
89
90 /* Font directory GC procedures */
91 private
ENUM_PTRS_WITH(font_dir_enum_ptrs,gs_font_dir * dir)92 ENUM_PTRS_WITH(font_dir_enum_ptrs, gs_font_dir *dir)
93 {
94 /* Enumerate pointers from cached characters to f/m pairs, */
95 /* and mark the cached character glyphs. */
96 /* See gxfcache.h for why we do this here. */
97 uint cci = index - st_font_dir_max_ptrs;
98 uint offset, count;
99 uint tmask = dir->ccache.table_mask;
100
101 if (cci == 0)
102 offset = 0, count = 1;
103 else if (cci == dir->enum_index + 1)
104 offset = dir->enum_offset + 1, count = 1;
105 else
106 offset = 0, count = cci;
107 for (; offset <= tmask; ++offset) {
108 cached_char *cc = dir->ccache.table[offset];
109
110 if (cc != 0 && !--count) {
111 (*dir->ccache.mark_glyph)
112 (mem, cc->code, dir->ccache.mark_glyph_data);
113 /****** HACK: break const. We'll fix this someday. ******/
114 ((gs_font_dir *)dir)->enum_index = cci;
115 ((gs_font_dir *)dir)->enum_offset = offset;
116 ENUM_RETURN(cc_pair(cc) - cc->pair_index);
117 }
118 }
119 }
120 return 0;
121 #define e1(i,elt) ENUM_PTR(i,gs_font_dir,elt);
122 font_dir_do_ptrs(e1)
123 #undef e1
124 ENUM_PTRS_END
125 private RELOC_PTRS_WITH(font_dir_reloc_ptrs, gs_font_dir *dir);
126 /* Relocate the pointers from cached characters to f/m pairs. */
127 /* See gxfcache.h for why we do this here. */
128 {
129 int chi;
130
131 for (chi = dir->ccache.table_mask; chi >= 0; --chi) {
132 cached_char *cc = dir->ccache.table[chi];
133
134 if (cc != 0)
135 cc_set_pair_only(cc,
136 (cached_fm_pair *)
137 RELOC_OBJ(cc_pair(cc) - cc->pair_index) +
138 cc->pair_index);
139 }
140 }
141 /* We have to relocate the cached characters before we */
142 /* relocate dir->ccache.table! */
143 RELOC_PTR(gs_font_dir, orig_fonts);
144 #define r1(i,elt) RELOC_PTR(gs_font_dir, elt);
font_dir_do_ptrs(r1)145 font_dir_do_ptrs(r1)
146 #undef r1
147 RELOC_PTRS_END
148
149 /* GC procedures for fonts */
150 /*
151 * When we finalize a base font, we unlink it from the orig_fonts list;
152 * when we finalize a scaled font, we unlink it from scaled_fonts.
153 * See above for more information.
154 */
155 void
156 gs_font_finalize(void *vptr)
157 {
158 gs_font *const pfont = vptr;
159 gs_font **ppfirst;
160 gs_font *next = pfont->next;
161 gs_font *prev = pfont->prev;
162
163 if_debug4('u', "[u]unlinking font 0x%lx, base=0x%lx, prev=0x%lx, next=0x%lx\n",
164 (ulong) pfont, (ulong) pfont->base, (ulong) prev, (ulong) next);
165 /* Notify clients that the font is being freed. */
166 gs_notify_all(&pfont->notify_list, NULL);
167 if (pfont->dir == 0)
168 ppfirst = 0;
169 else if (pfont->base == pfont)
170 ppfirst = &pfont->dir->orig_fonts;
171 else {
172 /*
173 * Track the number of cached scaled fonts. Only decrement the
174 * count if we didn't do this already in gs_makefont.
175 */
176 if (next || prev || pfont->dir->scaled_fonts == pfont)
177 pfont->dir->ssize--;
178 ppfirst = &pfont->dir->scaled_fonts;
179 }
180 /*
181 * gs_purge_font may have unlinked this font already:
182 * don't unlink it twice.
183 */
184 if (next != 0 && next->prev == pfont)
185 next->prev = prev;
186 if (prev != 0) {
187 if (prev->next == pfont)
188 prev->next = next;
189 } else if (ppfirst != 0 && *ppfirst == pfont)
190 *ppfirst = next;
191 gs_notify_release(&pfont->notify_list);
192 }
193 private
194 ENUM_PTRS_WITH(font_enum_ptrs, gs_font *pfont) return ENUM_USING(st_gs_notify_list, &pfont->notify_list, sizeof(gs_notify_list_t), index - 5);
195 /* We don't enumerate next or prev of base fonts. */
196 /* See above for details. */
197 case 0: ENUM_RETURN((pfont->base == pfont ? 0 : pfont->next));
198 case 1: ENUM_RETURN((pfont->base == pfont ? 0 : pfont->prev));
199 ENUM_PTR3(2, gs_font, dir, base, client_data);
200 ENUM_PTRS_END
201 private RELOC_PTRS_WITH(font_reloc_ptrs, gs_font *pfont);
202 RELOC_USING(st_gs_notify_list, &pfont->notify_list, sizeof(gs_notify_list_t));
203 /* We *do* always relocate next and prev. */
204 /* Again, see above for details. */
205 RELOC_PTR(gs_font, next);
206 RELOC_PTR(gs_font, prev);
207 RELOC_PTR3(gs_font, dir, base, client_data);
208 RELOC_PTRS_END
209
210 /* Allocate a font directory */
211 private bool
cc_no_mark_glyph(const gs_memory_t * mem,gs_glyph glyph,void * ignore_data)212 cc_no_mark_glyph(const gs_memory_t *mem, gs_glyph glyph, void *ignore_data)
213 {
214 return false;
215 }
216 gs_font_dir *
gs_font_dir_alloc2(gs_memory_t * struct_mem,gs_memory_t * bits_mem)217 gs_font_dir_alloc2(gs_memory_t * struct_mem, gs_memory_t * bits_mem)
218 {
219 gs_font_dir *pdir = 0;
220
221 #if !arch_small_memory
222 # ifdef DEBUG
223 if (!gs_debug_c('.'))
224 # endif
225 { /* Try allocating a very large cache. */
226 /* If this fails, allocate a small one. */
227 pdir = gs_font_dir_alloc2_limits(struct_mem, bits_mem,
228 smax_LARGE, bmax_LARGE, mmax_LARGE,
229 cmax_LARGE, blimit_LARGE);
230 }
231 if (pdir == 0)
232 #endif
233 pdir = gs_font_dir_alloc2_limits(struct_mem, bits_mem,
234 smax_SMALL, bmax_SMALL, mmax_SMALL,
235 cmax_SMALL, blimit_SMALL);
236 if (pdir == 0)
237 return 0;
238 pdir->ccache.mark_glyph = cc_no_mark_glyph;
239 pdir->ccache.mark_glyph_data = 0;
240 return pdir;
241 }
242 gs_font_dir *
gs_font_dir_alloc2_limits(gs_memory_t * struct_mem,gs_memory_t * bits_mem,uint smax,uint bmax,uint mmax,uint cmax,uint upper)243 gs_font_dir_alloc2_limits(gs_memory_t * struct_mem, gs_memory_t * bits_mem,
244 uint smax, uint bmax, uint mmax, uint cmax, uint upper)
245 {
246 gs_font_dir *pdir =
247 gs_alloc_struct(struct_mem, gs_font_dir, &st_font_dir,
248 "font_dir_alloc(dir)");
249 int code;
250
251 if (pdir == 0)
252 return 0;
253 code = gx_char_cache_alloc(struct_mem, bits_mem, pdir,
254 bmax, mmax, cmax, upper);
255 if (code < 0) {
256 gs_free_object(struct_mem, pdir, "font_dir_alloc(dir)");
257 return 0;
258 }
259 pdir->orig_fonts = 0;
260 pdir->scaled_fonts = 0;
261 pdir->ssize = 0;
262 pdir->smax = smax;
263 pdir->align_to_pixels = false;
264 pdir->glyph_to_unicode_table = NULL;
265 pdir->grid_fit_tt = 2;
266 pdir->memory = struct_mem;
267 pdir->tti = 0;
268 pdir->san = 0;
269 pdir->global_glyph_code = NULL;
270 return pdir;
271 }
272
273 /* Allocate and minimally initialize a font. */
274 gs_font *
gs_font_alloc(gs_memory_t * mem,gs_memory_type_ptr_t pstype,const gs_font_procs * procs,gs_font_dir * dir,client_name_t cname)275 gs_font_alloc(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
276 const gs_font_procs *procs, gs_font_dir *dir,
277 client_name_t cname)
278 {
279 gs_font *pfont = gs_alloc_struct(mem, gs_font, pstype, cname);
280
281 if (pfont == 0)
282 return 0;
283 #if 1 /* Clear entire structure to avoid unitialized pointers
284 when the initialization exits prematurely by error. */
285 memset(pfont, 0, pstype->ssize);
286 pfont->memory = mem;
287 pfont->dir = dir;
288 gs_font_notify_init(pfont);
289 pfont->id = gs_next_ids(mem, 1);
290 pfont->base = pfont;
291 pfont->ExactSize = pfont->InBetweenSize = pfont->TransformedChar =
292 fbit_use_outlines;
293 pfont->procs = *procs;
294 #else
295 /* For clarity we leave old initializations here
296 to know which fields needs to be initialized. */
297 pfont->next = pfont->prev = 0;
298 pfont->memory = mem;
299 pfont->dir = dir;
300 pfont->is_resource = false;
301 gs_font_notify_init(pfont);
302 pfont->id = gs_next_ids(mem, 1);
303 pfont->base = pfont;
304 pfont->client_data = 0;
305 /* not FontMatrix, FontType */
306 pfont->BitmapWidths = false;
307 pfont->ExactSize = pfont->InBetweenSize = pfont->TransformedChar =
308 fbit_use_outlines;
309 pfont->WMode = 0;
310 pfont->PaintType = 0;
311 pfont->StrokeWidth = 0;
312 pfont->procs = *procs;
313 memset(&pfont->orig_FontMatrix, 0, sizeof(pfont->orig_FontMatrix));
314 #endif
315 /* not key_name, font_name */
316 return pfont;
317 }
318 /* Allocate and minimally initialize a base font. */
319 gs_font_base *
gs_font_base_alloc(gs_memory_t * mem,gs_memory_type_ptr_t pstype,const gs_font_procs * procs,gs_font_dir * dir,client_name_t cname)320 gs_font_base_alloc(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
321 const gs_font_procs *procs, gs_font_dir *dir,
322 client_name_t cname)
323 {
324 gs_font_base *pfont =
325 (gs_font_base *)gs_font_alloc(mem, pstype, procs, dir, cname);
326
327 if (pfont == 0)
328 return 0;
329 pfont->FontBBox.p.x = pfont->FontBBox.p.y =
330 pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0;
331 uid_set_invalid(&pfont->UID);
332 pfont->encoding_index = pfont->nearest_encoding_index = -1;
333 return pfont;
334 }
335
336 /* Initialize the notification list for a font. */
337 void
gs_font_notify_init(gs_font * font)338 gs_font_notify_init(gs_font *font)
339 {
340 /*
341 * The notification list for a font must be allocated in the font's
342 * stable memory, because of the following possible sequence of events:
343 *
344 * - Allocate font X in local VM.
345 * - Client A registers for notification when X is freed.
346 * - 'save'
347 * - Client B registers for notification when X is freed.
348 * - 'restore'
349 *
350 * If the notification list element for client B is allocated in
351 * restorable local VM (i.e., the same VM as the font), then when the
352 * 'restore' occurs, either the list element will be deleted (not what
353 * client B wants, because font X hasn't been freed yet), or there will
354 * be a dangling pointer.
355 */
356 gs_notify_init(&font->notify_list, gs_memory_stable(font->memory));
357 }
358
359
360 /*
361 * Register/unregister a client for notification by a font. Currently
362 * the clients are only notified when a font is freed. Note that any
363 * such client must unregister itself when *it* is freed.
364 */
365 int
gs_font_notify_register(gs_font * font,gs_notify_proc_t proc,void * proc_data)366 gs_font_notify_register(gs_font *font, gs_notify_proc_t proc, void *proc_data)
367 {
368 return gs_notify_register(&font->notify_list, proc, proc_data);
369 }
370 int
gs_font_notify_unregister(gs_font * font,gs_notify_proc_t proc,void * proc_data)371 gs_font_notify_unregister(gs_font *font, gs_notify_proc_t proc, void *proc_data)
372 {
373 return gs_notify_unregister(&font->notify_list, proc, proc_data);
374 }
375
376 /* Link an element at the head of a chain. */
377 private void
font_link_first(gs_font ** pfirst,gs_font * elt)378 font_link_first(gs_font **pfirst, gs_font *elt)
379 {
380 gs_font *first = elt->next = *pfirst;
381
382 if (first)
383 first->prev = elt;
384 elt->prev = 0;
385 *pfirst = elt;
386 }
387
388 /* definefont */
389 /* Use this only for original (unscaled) fonts! */
390 /* Note that it expects pfont->procs.define_font to be set already. */
391 int
gs_definefont(gs_font_dir * pdir,gs_font * pfont)392 gs_definefont(gs_font_dir * pdir, gs_font * pfont)
393 {
394 int code;
395
396 pfont->dir = pdir;
397 pfont->base = pfont;
398 code = (*pfont->procs.define_font) (pdir, pfont);
399 if (code < 0) { /* Make sure we don't try to finalize this font. */
400 pfont->base = 0;
401 return code;
402 }
403 font_link_first(&pdir->orig_fonts, pfont);
404 if_debug2('m', "[m]defining font 0x%lx, next=0x%lx\n",
405 (ulong) pfont, (ulong) pfont->next);
406 return 0;
407 }
408
409 /* Find a sililar registered font of same type. */
410 int
gs_font_find_similar(const gs_font_dir * pdir,const gs_font ** ppfont,int (* similar)(const gs_font *,const gs_font *))411 gs_font_find_similar(const gs_font_dir * pdir, const gs_font **ppfont,
412 int (*similar)(const gs_font *, const gs_font *))
413 {
414 const gs_font *pfont0 = *ppfont;
415 const gs_font *pfont1 = pdir->orig_fonts;
416
417 for (; pfont1 != NULL; pfont1 = pfont1->next) {
418 if (pfont1 != pfont0 && pfont1->FontType == pfont0->FontType) {
419 int code = similar(pfont0, pfont1);
420 if (code != 0) {
421 *ppfont = pfont1;
422 return code;
423 }
424 }
425 }
426 return 0;
427 }
428
429 /* scalefont */
430 int
gs_scalefont(gs_font_dir * pdir,const gs_font * pfont,floatp scale,gs_font ** ppfont)431 gs_scalefont(gs_font_dir * pdir, const gs_font * pfont, floatp scale,
432 gs_font ** ppfont)
433 {
434 gs_matrix mat;
435
436 gs_make_scaling(scale, scale, &mat);
437 return gs_makefont(pdir, pfont, &mat, ppfont);
438 }
439
440 /* makefont */
441 int
gs_makefont(gs_font_dir * pdir,const gs_font * pfont,const gs_matrix * pmat,gs_font ** ppfont)442 gs_makefont(gs_font_dir * pdir, const gs_font * pfont,
443 const gs_matrix * pmat, gs_font ** ppfont)
444 {
445 int code;
446 gs_font *prev = 0;
447 gs_font *pf_out = pdir->scaled_fonts;
448 gs_memory_t *mem = pfont->memory;
449 gs_matrix newmat;
450 bool can_cache;
451
452 if ((code = gs_matrix_multiply(&pfont->FontMatrix, pmat, &newmat)) < 0)
453 return code;
454 /*
455 * Check for the font already being in the scaled font cache.
456 * Until version 5.97, we only cached scaled fonts if the base
457 * (unscaled) font had a valid UniqueID or XUID; now, we will cache
458 * scaled versions of any non-composite font.
459 */
460 #ifdef DEBUG
461 if (gs_debug_c('m')) {
462 const gs_font_base *const pbfont = (const gs_font_base *)pfont;
463
464 if (pfont->FontType == ft_composite)
465 dlprintf("[m]composite");
466 else if (uid_is_UniqueID(&pbfont->UID))
467 dlprintf1("[m]UniqueID=%ld", pbfont->UID.id);
468 else if (uid_is_XUID(&pbfont->UID))
469 dlprintf1("[m]XUID(%u)", (uint) (-pbfont->UID.id));
470 else
471 dlprintf("[m]no UID");
472 dprintf7(", FontType=%d,\n[m] new FontMatrix=[%g %g %g %g %g %g]\n",
473 pfont->FontType,
474 pmat->xx, pmat->xy, pmat->yx, pmat->yy,
475 pmat->tx, pmat->ty);
476 }
477 #endif
478 /*
479 * Don't try to cache scaled composite fonts, because of the side
480 * effects on FDepVector and descendant fonts that occur in makefont.
481 */
482 if (pfont->FontType != ft_composite) {
483 for (; pf_out != 0; prev = pf_out, pf_out = pf_out->next)
484 if (pf_out->FontType == pfont->FontType &&
485 pf_out->base == pfont->base &&
486 pf_out->FontMatrix.xx == newmat.xx &&
487 pf_out->FontMatrix.xy == newmat.xy &&
488 pf_out->FontMatrix.yx == newmat.yx &&
489 pf_out->FontMatrix.yy == newmat.yy &&
490 pf_out->FontMatrix.tx == newmat.tx &&
491 pf_out->FontMatrix.ty == newmat.ty
492 ) {
493 *ppfont = pf_out;
494 if_debug1('m', "[m]found font=0x%lx\n", (ulong) pf_out);
495 return 0;
496 }
497 can_cache = true;
498 } else
499 can_cache = false;
500 pf_out = gs_alloc_struct(mem, gs_font, gs_object_type(mem, pfont),
501 "gs_makefont");
502 if (!pf_out)
503 return_error(gs_error_VMerror);
504 memcpy(pf_out, pfont, gs_object_size(mem, pfont));
505 gs_font_notify_init(pf_out);
506 pf_out->FontMatrix = newmat;
507 pf_out->client_data = 0;
508 pf_out->dir = pdir;
509 pf_out->base = pfont->base;
510 *ppfont = pf_out;
511 code = (*pf_out->procs.make_font) (pdir, pfont, pmat, ppfont);
512 if (code < 0)
513 return code;
514 if (can_cache) {
515 if (pdir->ssize >= pdir->smax && prev != 0) {
516 /*
517 * We must discard a cached scaled font.
518 * prev points to the last (oldest) font.
519 * (We can't free it, because there might be
520 * other references to it.)
521 */
522 if_debug1('m', "[m]discarding font 0x%lx\n",
523 (ulong) prev);
524 if (prev->prev != 0)
525 prev->prev->next = 0;
526 else
527 pdir->scaled_fonts = 0;
528 pdir->ssize--;
529 prev->prev = 0;
530 if (prev->FontType != ft_composite) {
531 if_debug1('m', "[m]discarding UID 0x%lx\n",
532 (ulong) ((gs_font_base *) prev)->
533 UID.xvalues);
534 uid_free(&((gs_font_base *) prev)->UID,
535 prev->memory,
536 "gs_makefont(discarding)");
537 uid_set_invalid(&((gs_font_base *) prev)->UID);
538 }
539 }
540 pdir->ssize++;
541 font_link_first(&pdir->scaled_fonts, pf_out);
542 } else { /* Prevent garbage pointers. */
543 pf_out->next = pf_out->prev = 0;
544 }
545 if_debug2('m', "[m]new font=0x%lx can_cache=%s\n",
546 (ulong) * ppfont, (can_cache ? "true" : "false"));
547 return 1;
548 }
549
550 /* Set the current font. This is provided only for the benefit of cshow, */
551 /* which must reset the current font without disturbing the root font. */
552 void
gs_set_currentfont(gs_state * pgs,gs_font * pfont)553 gs_set_currentfont(gs_state * pgs, gs_font * pfont)
554 {
555 pgs->font = pfont;
556 pgs->char_tm_valid = false;
557 }
558
559 /* setfont */
560 int
gs_setfont(gs_state * pgs,gs_font * pfont)561 gs_setfont(gs_state * pgs, gs_font * pfont)
562 {
563 pgs->font = pgs->root_font = pfont;
564 pgs->char_tm_valid = false;
565 return 0;
566 }
567
568 /* currentfont */
569 gs_font *
gs_currentfont(const gs_state * pgs)570 gs_currentfont(const gs_state * pgs)
571 {
572 return pgs->font;
573 }
574
575 /* rootfont */
576 gs_font *
gs_rootfont(const gs_state * pgs)577 gs_rootfont(const gs_state * pgs)
578 {
579 return pgs->root_font;
580 }
581
582 /* cachestatus */
583 void
gs_cachestatus(register const gs_font_dir * pdir,register uint pstat[7])584 gs_cachestatus(register const gs_font_dir * pdir, register uint pstat[7])
585 {
586 pstat[0] = pdir->ccache.bsize;
587 pstat[1] = pdir->ccache.bmax;
588 pstat[2] = pdir->fmcache.msize;
589 pstat[3] = pdir->fmcache.mmax;
590 pstat[4] = pdir->ccache.csize;
591 pstat[5] = pdir->ccache.cmax;
592 pstat[6] = pdir->ccache.upper;
593 }
594
595 /* setcacheparams */
596 int
gs_setcachesize(gs_font_dir * pdir,uint size)597 gs_setcachesize(gs_font_dir * pdir, uint size)
598 { /* This doesn't delete anything from the cache yet. */
599 pdir->ccache.bmax = size;
600 return 0;
601 }
602 int
gs_setcachelower(gs_font_dir * pdir,uint size)603 gs_setcachelower(gs_font_dir * pdir, uint size)
604 {
605 pdir->ccache.lower = size;
606 return 0;
607 }
608 int
gs_setcacheupper(gs_font_dir * pdir,uint size)609 gs_setcacheupper(gs_font_dir * pdir, uint size)
610 {
611 pdir->ccache.upper = size;
612 return 0;
613 }
614 int
gs_setaligntopixels(gs_font_dir * pdir,uint v)615 gs_setaligntopixels(gs_font_dir * pdir, uint v)
616 {
617 pdir->align_to_pixels = v;
618 return 0;
619 }
620 int
gs_setgridfittt(gs_font_dir * pdir,uint v)621 gs_setgridfittt(gs_font_dir * pdir, uint v)
622 {
623 pdir->grid_fit_tt = v;
624 return 0;
625 }
626
627 /* currentcacheparams */
628 uint
gs_currentcachesize(const gs_font_dir * pdir)629 gs_currentcachesize(const gs_font_dir * pdir)
630 {
631 return pdir->ccache.bmax;
632 }
633 uint
gs_currentcachelower(const gs_font_dir * pdir)634 gs_currentcachelower(const gs_font_dir * pdir)
635 {
636 return pdir->ccache.lower;
637 }
638 uint
gs_currentcacheupper(const gs_font_dir * pdir)639 gs_currentcacheupper(const gs_font_dir * pdir)
640 {
641 return pdir->ccache.upper;
642 }
643 uint
gs_currentaligntopixels(const gs_font_dir * pdir)644 gs_currentaligntopixels(const gs_font_dir * pdir)
645 {
646 return pdir->align_to_pixels;
647 }
648 uint
gs_currentgridfittt(const gs_font_dir * pdir)649 gs_currentgridfittt(const gs_font_dir * pdir)
650 {
651 return pdir->grid_fit_tt;
652 }
653
654 /* Purge a font from all font- and character-related tables. */
655 /* This is only used by restore (and, someday, the GC). */
656 void
gs_purge_font(gs_font * pfont)657 gs_purge_font(gs_font * pfont)
658 {
659 gs_font_dir *pdir = pfont->dir;
660 gs_font *pf;
661
662 /* Remove the font from its list (orig_fonts or scaled_fonts). */
663 gs_font *prev = pfont->prev;
664 gs_font *next = pfont->next;
665
666 if (next != 0)
667 next->prev = prev, pfont->next = 0;
668 if (prev != 0)
669 prev->next = next, pfont->prev = 0;
670 else if (pdir->orig_fonts == pfont)
671 pdir->orig_fonts = next;
672 else if (pdir->scaled_fonts == pfont)
673 pdir->scaled_fonts = next;
674 else { /* Shouldn't happen! */
675 lprintf1("purged font 0x%lx not found\n", (ulong) pfont);
676 }
677
678 /* Purge the font from the scaled font cache. */
679 for (pf = pdir->scaled_fonts; pf != 0;) {
680 if (pf->base == pfont) {
681 gs_purge_font(pf);
682 pf = pdir->scaled_fonts; /* start over */
683 } else
684 pf = pf->next;
685 }
686
687 /* Purge the font from the font/matrix pair cache, */
688 /* including all cached characters rendered with that font. */
689 gs_purge_font_from_char_caches(pdir, pfont);
690
691 }
692
693 /* Locate a gs_font by gs_id. */
694 gs_font *
gs_find_font_by_id(gs_font_dir * pdir,gs_id id,gs_matrix * FontMatrix)695 gs_find_font_by_id(gs_font_dir *pdir, gs_id id, gs_matrix *FontMatrix)
696 {
697 gs_font *pfont = pdir->orig_fonts;
698
699 for(; pfont != NULL; pfont = pfont->next)
700 if(pfont->id == id &&
701 !memcmp(&pfont->FontMatrix, FontMatrix, sizeof(pfont->FontMatrix)))
702 return pfont;
703 return NULL;
704 }
705
706 /* ---------------- Default font procedures ---------------- */
707
708 /* ------ Font-level procedures ------ */
709
710 /* Default (vacuous) definefont handler. */
711 int
gs_no_define_font(gs_font_dir * pdir,gs_font * pfont)712 gs_no_define_font(gs_font_dir * pdir, gs_font * pfont)
713 {
714 return 0;
715 }
716
717 /* Default (vacuous) makefont handler. */
718 int
gs_no_make_font(gs_font_dir * pdir,const gs_font * pfont,const gs_matrix * pmat,gs_font ** ppfont)719 gs_no_make_font(gs_font_dir * pdir, const gs_font * pfont,
720 const gs_matrix * pmat, gs_font ** ppfont)
721 {
722 return 0;
723 }
724 /* Makefont handler for base fonts, which must copy the XUID. */
725 int
gs_base_make_font(gs_font_dir * pdir,const gs_font * pfont,const gs_matrix * pmat,gs_font ** ppfont)726 gs_base_make_font(gs_font_dir * pdir, const gs_font * pfont,
727 const gs_matrix * pmat, gs_font ** ppfont)
728 {
729 return uid_copy(&((gs_font_base *)*ppfont)->UID, (*ppfont)->memory,
730 "gs_base_make_font(XUID)");
731 }
732
733 /* Default font info procedure */
734 int
gs_default_font_info(gs_font * font,const gs_point * pscale,int members,gs_font_info_t * info)735 gs_default_font_info(gs_font *font, const gs_point *pscale, int members,
736 gs_font_info_t *info)
737 {
738 int wmode = font->WMode;
739 gs_font_base *bfont = (gs_font_base *)font;
740 gs_point scale;
741 gs_matrix smat;
742 const gs_matrix *pmat;
743
744 if (pscale == 0) {
745 scale.x = scale.y = 0;
746 pmat = 0;
747 } else {
748 scale = *pscale;
749 gs_make_scaling(scale.x, scale.y, &smat);
750 pmat = &smat;
751 }
752 info->members = 0;
753 if (members & FONT_INFO_FLAGS)
754 info->Flags_returned = 0;
755 if (font->FontType == ft_composite)
756 return 0; /* nothing available */
757 if (members & FONT_INFO_BBOX) {
758 info->BBox.p.x = (int)bfont->FontBBox.p.x;
759 info->BBox.p.y = (int)bfont->FontBBox.p.y;
760 info->BBox.q.x = (int)bfont->FontBBox.q.x;
761 info->BBox.q.y = (int)bfont->FontBBox.q.y;
762 info->Flags_returned |= FONT_INFO_BBOX;
763 }
764 if ((members & FONT_INFO_FLAGS) &&
765 (info->Flags_requested & FONT_IS_FIXED_WIDTH)
766 ) {
767 /*
768 * Scan the glyph space to compute the fixed width if any.
769 */
770 gs_glyph notdef = gs_no_glyph;
771 gs_glyph glyph;
772 int fixed_width = 0;
773 int index;
774 int code = 0; /* Quiet compiler. */
775
776 for (index = 0;
777 fixed_width >= 0 &&
778 (code = font->procs.enumerate_glyph(font, &index, GLYPH_SPACE_NAME, &glyph)) >= 0 &&
779 index != 0;
780 ) {
781 gs_glyph_info_t glyph_info;
782
783 code = font->procs.glyph_info(font, glyph, pmat,
784 (GLYPH_INFO_WIDTH0 << wmode),
785 &glyph_info);
786 if (code < 0)
787 return code;
788 if (notdef == gs_no_glyph && gs_font_glyph_is_notdef(bfont, glyph)) {
789 notdef = glyph;
790 info->MissingWidth = (int)glyph_info.width[wmode].x;
791 info->members |= FONT_INFO_MISSING_WIDTH;
792 }
793 if (glyph_info.width[wmode].y != 0)
794 fixed_width = min_int;
795 else if (fixed_width == 0)
796 fixed_width = (int)glyph_info.width[wmode].x;
797 else if (glyph_info.width[wmode].x != fixed_width)
798 fixed_width = min_int;
799 }
800 if (code < 0)
801 return code;
802 if (fixed_width > 0) {
803 info->Flags |= FONT_IS_FIXED_WIDTH;
804 info->members |= FONT_INFO_AVG_WIDTH | FONT_INFO_MAX_WIDTH |
805 FONT_INFO_MISSING_WIDTH;
806 info->AvgWidth = info->MaxWidth = info->MissingWidth = fixed_width;
807 }
808 info->Flags_returned |= FONT_IS_FIXED_WIDTH;
809 } else if (members & FONT_INFO_MISSING_WIDTH) {
810 gs_glyph glyph;
811 int index;
812
813 for (index = 0;
814 font->procs.enumerate_glyph(font, &index, GLYPH_SPACE_NAME, &glyph) >= 0 &&
815 index != 0;
816 ) {
817 /*
818 * If this is a CIDFont or TrueType font that uses integers as
819 * glyph names, check for glyph 0; otherwise, check for .notdef.
820 */
821 if (!gs_font_glyph_is_notdef(bfont, glyph))
822 continue;
823 {
824 gs_glyph_info_t glyph_info;
825 int code = font->procs.glyph_info(font, glyph, pmat,
826 (GLYPH_INFO_WIDTH0 << wmode),
827 &glyph_info);
828
829 if (code < 0)
830 return code;
831 info->MissingWidth = (int)glyph_info.width[wmode].x;
832 info->members |= FONT_INFO_MISSING_WIDTH;
833 break;
834 }
835 }
836 }
837 return 0;
838 }
839
840 /* Default font similarity testing procedure */
841 int
gs_default_same_font(const gs_font * font,const gs_font * ofont,int mask)842 gs_default_same_font(const gs_font *font, const gs_font *ofont, int mask)
843 {
844 while (font->base != font)
845 font = font->base;
846 while (ofont->base != ofont)
847 ofont = ofont->base;
848 if (ofont == font)
849 return mask;
850 /* In general, we can't determine similarity. */
851 return 0;
852 }
853 int
gs_base_same_font(const gs_font * font,const gs_font * ofont,int mask)854 gs_base_same_font(const gs_font *font, const gs_font *ofont, int mask)
855 {
856 int same = gs_default_same_font(font, ofont, mask);
857
858 if (!same) {
859 const gs_font_base *const bfont = (const gs_font_base *)font;
860 const gs_font_base *const obfont = (const gs_font_base *)ofont;
861
862 if (mask & FONT_SAME_ENCODING) {
863 if (bfont->encoding_index != ENCODING_INDEX_UNKNOWN ||
864 obfont->encoding_index != ENCODING_INDEX_UNKNOWN
865 ) {
866 if (bfont->encoding_index == obfont->encoding_index)
867 same |= FONT_SAME_ENCODING;
868 }
869 }
870 }
871 return same;
872 }
873
874 /* ------ Glyph-level procedures ------ */
875
876 /*
877 * Test whether a glyph is the notdef glyph for a base font.
878 * The test is somewhat adhoc: perhaps this should be a virtual procedure.
879 */
880 bool
gs_font_glyph_is_notdef(gs_font_base * bfont,gs_glyph glyph)881 gs_font_glyph_is_notdef(gs_font_base *bfont, gs_glyph glyph)
882 {
883 gs_const_string gnstr;
884
885 if (glyph == gs_no_glyph)
886 return false;
887 if (glyph >= gs_min_cid_glyph)
888 return (glyph == gs_min_cid_glyph);
889 return (bfont->procs.glyph_name((gs_font *)bfont, glyph, &gnstr) >= 0 &&
890 gnstr.size == 7 && !memcmp(gnstr.data, ".notdef", 7));
891 }
892
893 /* Dummy character encoding procedure */
894 gs_glyph
gs_no_encode_char(gs_font * pfont,gs_char chr,gs_glyph_space_t glyph_space)895 gs_no_encode_char(gs_font *pfont, gs_char chr, gs_glyph_space_t glyph_space)
896 {
897 return gs_no_glyph;
898 }
899
900 /* Dummy glyph decoding procedure */
901 gs_char
gs_no_decode_glyph(gs_font * pfont,gs_glyph glyph)902 gs_no_decode_glyph(gs_font *pfont, gs_glyph glyph)
903 {
904 return GS_NO_CHAR;
905 }
906
907 /* Dummy glyph enumeration procedure */
908 int
gs_no_enumerate_glyph(gs_font * font,int * pindex,gs_glyph_space_t glyph_space,gs_glyph * pglyph)909 gs_no_enumerate_glyph(gs_font *font, int *pindex, gs_glyph_space_t glyph_space,
910 gs_glyph *pglyph)
911 {
912 return_error(gs_error_undefined);
913 }
914
915 /* Default glyph info procedure */
916 int
gs_default_glyph_info(gs_font * font,gs_glyph glyph,const gs_matrix * pmat,int members,gs_glyph_info_t * info)917 gs_default_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
918 int members, gs_glyph_info_t *info)
919 { /* WMode may be inherited from an upper font. */
920 gx_path path;
921 int returned = 0;
922 int code;
923 int wmode = ((members & GLYPH_INFO_WIDTH1) != 0);
924 double sbw[4] = {0, 0, 0, 0};
925 /* Currently glyph_outline retrieves sbw only with type 1,2,9 fonts. */
926 bool charstrings_font = (font->FontType == ft_encrypted ||
927 font->FontType == ft_encrypted2 ||
928 font->FontType == ft_CID_encrypted);
929
930 gx_path_init_bbox_accumulator(&path);
931 code = gx_path_add_point(&path, fixed_0, fixed_0);
932 if (code < 0)
933 goto out;
934 code = font->procs.glyph_outline(font, wmode, glyph, pmat, &path, sbw);
935 if (code < 0)
936 goto out;
937 if (members & GLYPH_INFO_WIDTHS) {
938 int wmode = font->WMode;
939 int wmask = GLYPH_INFO_WIDTH0 << wmode;
940
941 if (members & wmask) {
942 gs_fixed_point pt;
943
944 code = gx_path_current_point(&path, &pt);
945 if (code < 0)
946 goto out;
947 info->width[wmode].x = fixed2float(pt.x);
948 info->width[wmode].y = fixed2float(pt.y);
949 returned |= wmask;
950 }
951 }
952 if (members & GLYPH_INFO_BBOX) {
953 gs_fixed_rect bbox;
954
955 code = gx_path_bbox(&path, &bbox);
956 if (code < 0)
957 goto out;
958 info->bbox.p.x = fixed2float(bbox.p.x);
959 info->bbox.p.y = fixed2float(bbox.p.y);
960 info->bbox.q.x = fixed2float(bbox.q.x);
961 info->bbox.q.y = fixed2float(bbox.q.y);
962 returned |= GLYPH_INFO_BBOX;
963 }
964 if (members & (GLYPH_INFO_WIDTH0 << wmode) && charstrings_font) {
965 if (pmat == 0) {
966 info->width[wmode].x = sbw[2];
967 info->width[wmode].y = sbw[3];
968 } else {
969 code = gs_distance_transform(sbw[2], sbw[3], pmat, &info->width[wmode]);
970 if (code < 0)
971 return code;
972 }
973 returned |= GLYPH_INFO_WIDTH0 << wmode;
974 }
975 if (members & (GLYPH_INFO_VVECTOR0 << wmode) && charstrings_font) {
976 if (pmat == 0) {
977 info->v.x = sbw[0];
978 info->v.y = sbw[1];
979 } else {
980 gs_distance_transform(sbw[0], sbw[1], pmat, &info->v);
981 if (code < 0)
982 return code;
983 }
984 returned |= GLYPH_INFO_VVECTOR0 << wmode;
985 }
986 if (members & GLYPH_INFO_NUM_PIECES) {
987 info->num_pieces = 0;
988 returned |= GLYPH_INFO_NUM_PIECES;
989 }
990 returned |= members & GLYPH_INFO_PIECES; /* no pieces stored */
991 out:
992 info->members = returned;
993 return code;
994 }
995
996 /* Dummy glyph outline procedure */
997 int
gs_no_glyph_outline(gs_font * font,int WMode,gs_glyph glyph,const gs_matrix * pmat,gx_path * ppath,double sbw[4])998 gs_no_glyph_outline(gs_font *font, int WMode, gs_glyph glyph, const gs_matrix *pmat,
999 gx_path *ppath, double sbw[4])
1000 {
1001 return_error(gs_error_undefined);
1002 }
1003
1004 /* Dummy glyph name procedure */
1005 int
gs_no_glyph_name(gs_font * font,gs_glyph glyph,gs_const_string * pstr)1006 gs_no_glyph_name(gs_font *font, gs_glyph glyph, gs_const_string *pstr)
1007 {
1008 return_error(gs_error_undefined);
1009 }
1010
1011