xref: /plan9/sys/src/cmd/gs/src/gsfont.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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