Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/gs/src/gsfont.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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 
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);
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
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 *
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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 *
570
gs_currentfont(const gs_state * pgs)
571
{
572
    return pgs->font;
573
}
574
 
575
/* rootfont */
576
gs_font *
577
gs_rootfont(const gs_state * pgs)
578
{
579
    return pgs->root_font;
580
}
581
 
582
/* cachestatus */
583
void
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
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
603
gs_setcachelower(gs_font_dir * pdir, uint size)
604
{
605
    pdir->ccache.lower = size;
606
    return 0;
607
}
608
int
609
gs_setcacheupper(gs_font_dir * pdir, uint size)
610
{
611
    pdir->ccache.upper = size;
612
    return 0;
613
}
614
int
615
gs_setaligntopixels(gs_font_dir * pdir, uint v)
616
{
617
    pdir->align_to_pixels = v;
618
    return 0;
619
}
620
int
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
629
gs_currentcachesize(const gs_font_dir * pdir)
630
{
631
    return pdir->ccache.bmax;
632
}
633
uint
634
gs_currentcachelower(const gs_font_dir * pdir)
635
{
636
    return pdir->ccache.lower;
637
}
638
uint
639
gs_currentcacheupper(const gs_font_dir * pdir)
640
{
641
    return pdir->ccache.upper;
642
}
643
uint
644
gs_currentaligntopixels(const gs_font_dir * pdir)
645
{
646
    return pdir->align_to_pixels;
647
}
648
uint
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
1006
gs_no_glyph_name(gs_font *font, gs_glyph glyph, gs_const_string *pstr)
1007
{
1008
    return_error(gs_error_undefined);
1009
}
1010