Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989, 1995, 1996, 1997, 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: gxccman.c,v 1.30 2004/12/08 21:35:13 stefan Exp $ */
18
/* Character cache management routines for Ghostscript library */
19
#include "gx.h"
20
#include "memory_.h"
21
#include "gpcheck.h"
22
#include "gserrors.h"
23
#include "gsstruct.h"
24
#include "gsbitops.h"
25
#include "gsutil.h"		/* for gs_next_ids */
26
#include "gxfixed.h"
27
#include "gxmatrix.h"
28
#include "gzstate.h"
29
#include "gxpath.h"
30
#include "gxdevice.h"
31
#include "gxdevmem.h"
32
#include "gxchar.h"
33
#include "gxfont.h"
34
#include "gxfcache.h"
35
#include "gxxfont.h"
36
#include "gxttfb.h"
37
#include "gxfont42.h"
38
#include <assert.h>
39
 
40
/* Define the descriptors for the cache structures. */
41
private_st_cached_fm_pair();
42
private_st_cached_fm_pair_elt();
43
/*private_st_cached_char(); *//* unused */
44
private_st_cached_char_ptr();	/* unused */
45
private_st_cached_char_ptr_elt();
46
/*
47
 * Define a descriptor for the cache data.  This is equivalent to st_bytes,
48
 * but it identifies the cache data as such in a memory dump.
49
 */
50
gs_private_st_simple(st_font_cache_bytes, byte, "font cache bytes");
51
/* GC procedures */
52
/* We do all the work in font_dir_enum/reloc_ptrs in gsfont.c. */
53
/* See gxfcache.h for details. */
54
private 
55
ENUM_PTRS_BEGIN(cc_ptr_enum_ptrs) return 0;
56
 
57
ENUM_PTRS_END
58
private RELOC_PTRS_BEGIN(cc_ptr_reloc_ptrs)
59
{
60
}
61
RELOC_PTRS_END
62
 
63
/* Forward references */
64
private gx_xfont * lookup_xfont_by_name(gx_device *, const gx_xfont_procs *, gs_font_name *, int, const cached_fm_pair *, const gs_matrix *);
65
private cached_char *alloc_char(gs_font_dir *, ulong);
66
private cached_char *alloc_char_in_chunk(gs_font_dir *, ulong);
67
private void hash_remove_cached_char(gs_font_dir *, uint);
68
private void shorten_cached_char(gs_font_dir *, cached_char *, uint);
69
 
70
/* ====== Initialization ====== */
71
 
72
/* Allocate and initialize the character cache elements of a font directory. */
73
int
74
gx_char_cache_alloc(gs_memory_t * struct_mem, gs_memory_t * bits_mem,
75
	    gs_font_dir * pdir, uint bmax, uint mmax, uint cmax, uint upper)
76
{				/* Since we use open hashing, we must increase cmax somewhat. */
77
    uint chsize = (cmax + (cmax >> 1)) | 31;
78
    cached_fm_pair *mdata;
79
    cached_char **chars;
80
 
81
    /* Round up chsize to a power of 2. */
82
    while (chsize & (chsize + 1))
83
	chsize |= chsize >> 1;
84
    chsize++;
85
    mdata = gs_alloc_struct_array(struct_mem, mmax, cached_fm_pair,
86
				  &st_cached_fm_pair_element,
87
				  "font_dir_alloc(mdata)");
88
    chars = gs_alloc_struct_array(struct_mem, chsize, cached_char *,
89
				  &st_cached_char_ptr_element,
90
				  "font_dir_alloc(chars)");
91
    if (mdata == 0 || chars == 0) {
92
	gs_free_object(struct_mem, chars, "font_dir_alloc(chars)");
93
	gs_free_object(struct_mem, mdata, "font_dir_alloc(mdata)");
94
	return_error(gs_error_VMerror);
95
    }
96
    pdir->fmcache.mmax = mmax;
97
    pdir->fmcache.mdata = mdata;
98
    pdir->ccache.struct_memory = struct_mem;
99
    pdir->ccache.bits_memory = bits_mem;
100
    pdir->ccache.bmax = bmax;
101
    pdir->ccache.cmax = cmax;
102
    pdir->ccache.lower = upper / 10;
103
    pdir->ccache.upper = upper;
104
    pdir->ccache.table = chars;
105
    pdir->ccache.table_mask = chsize - 1;
106
    gx_char_cache_init(pdir);
107
    return 0;
108
}
109
 
110
/* Initialize the character cache. */
111
void
112
gx_char_cache_init(register gs_font_dir * dir)
113
{
114
    int i;
115
    cached_fm_pair *pair;
116
    char_cache_chunk *cck = (char_cache_chunk *)
117
    gs_alloc_bytes_immovable(dir->ccache.bits_memory,
118
			     sizeof(char_cache_chunk),
119
			     "initial_chunk");
120
 
121
    dir->fmcache.msize = 0;
122
    dir->fmcache.mnext = 0;
123
    gx_bits_cache_chunk_init(cck, NULL, 0);
124
    gx_bits_cache_init((gx_bits_cache *) & dir->ccache, cck);
125
    dir->ccache.bspace = 0;
126
    memset((char *)dir->ccache.table, 0,
127
	   (dir->ccache.table_mask + 1) * sizeof(cached_char *));
128
    for (i = 0, pair = dir->fmcache.mdata;
129
	 i < dir->fmcache.mmax; i++, pair++) {
130
	pair->index = i;
131
	fm_pair_init(pair);
132
	pair->ttf = 0;
133
	pair->ttr = 0;
134
    }
135
}
136
 
137
/* ====== Purging ====== */
138
 
139
/* Purge from the character cache all entries selected by */
140
/* a client-supplied procedure. */
141
void
142
gx_purge_selected_cached_chars(gs_font_dir * dir,
143
			       bool(*proc) (const gs_memory_t *mem, 
144
					    cached_char *, void *), 
145
			       void *proc_data)
146
{
147
    int chi;
148
    int cmax = dir->ccache.table_mask;
149
 
150
    for (chi = 0; chi <= cmax;) {
151
	cached_char *cc = dir->ccache.table[chi];
152
 
153
	if (cc != 0 && (*proc) (dir->memory, cc, proc_data)) {
154
	    hash_remove_cached_char(dir, chi);
155
	    gx_free_cached_char(dir, cc);
156
	} else
157
	    chi++;
158
    }
159
}
160
 
161
/* ====== Font-level routines ====== */
162
 
163
/* Add a font/matrix pair to the cache. */
164
/* (This is only exported for gxccache.c.) */
165
int
166
gx_add_fm_pair(register gs_font_dir * dir, gs_font * font, const gs_uid * puid,
167
	       const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
168
	       bool design_grid, cached_fm_pair **ppair)
169
{
170
    float mxx, mxy, myx, myy;
171
    register cached_fm_pair *pair = dir->fmcache.mdata + dir->fmcache.mnext;
172
    cached_fm_pair *mend = dir->fmcache.mdata + dir->fmcache.mmax;
173
 
174
    gx_compute_ccache_key(font, char_tm, log2_scale, design_grid,
175
			    &mxx, &mxy, &myx, &myy);
176
    if (dir->fmcache.msize == dir->fmcache.mmax) {	/* cache is full *//* Prefer an entry with num_chars == 0, if any. */
177
	int count;
178
 
179
	for (count = dir->fmcache.mmax;
180
	     --count >= 0 && pair->num_chars != 0;
181
	    )
182
	    if (++pair == mend)
183
		pair = dir->fmcache.mdata;
184
	gs_purge_fm_pair(dir, pair, 0);
185
    } else {			/* Look for an empty entry.  (We know there is one.) */
186
	while (!fm_pair_is_free(pair))
187
	    if (++pair == mend)
188
		pair = dir->fmcache.mdata;
189
    }
190
    dir->fmcache.msize++;
191
    dir->fmcache.mnext = pair + 1 - dir->fmcache.mdata;
192
    if (dir->fmcache.mnext == dir->fmcache.mmax)
193
	dir->fmcache.mnext = 0;
194
    pair->font = font;
195
    pair->UID = *puid;
196
    pair->FontType = font->FontType;
197
    /* The OSF/1 compiler doesn't like casting a pointer to */
198
    /* a shorter int.... */
199
    pair->hash = (uint) (ulong) pair % 549;	/* scramble bits */
200
    pair->mxx = mxx, pair->mxy = mxy;
201
    pair->myx = myx, pair->myy = myy;
202
    pair->num_chars = 0;
203
    pair->xfont_tried = false;
204
    pair->xfont = 0;
205
    pair->ttf = 0;
206
    pair->ttr = 0;
207
    pair->design_grid = false;
208
    if (font->FontType == ft_TrueType || font->FontType == ft_CID_TrueType) 
209
	if (((gs_font_type42 *)font)->FAPI==NULL) {
210
	    int code; 
211
	    float cxx, cxy, cyx, cyy;
212
	    gs_matrix m;
213
	    gx_compute_char_matrix(char_tm, log2_scale, &cxx, &cxy, &cyx, &cyy);
214
 
215
	    pair->design_grid = design_grid;
216
	    m.xx = cxx;
217
	    m.xy = cxy;
218
	    m.yx = cyx;
219
	    m.yy = cyy;
220
	    m.tx = m.ty = 0;
221
	    pair->ttr = gx_ttfReader__create(dir->memory);
222
	    if (!pair->ttr)
223
		return_error(gs_error_VMerror);
224
	    /*  We could use a single the reader instance for all fonts ... */
225
	    pair->ttf = ttfFont__create(dir);
226
	    if (!pair->ttf)
227
		return_error(gs_error_VMerror);
228
	    gx_ttfReader__set_font(pair->ttr, (gs_font_type42 *)font);
229
	    code = ttfFont__Open_aux(pair->ttf, dir->tti, pair->ttr, 
230
			(gs_font_type42 *)font, &m, log2_scale, design_grid);
231
	    gx_ttfReader__set_font(pair->ttr, NULL);
232
	    if (code < 0)
233
		return code;
234
	}
235
    pair->memory = 0;
236
    if_debug8('k', "[k]adding pair 0x%lx: font=0x%lx [%g %g %g %g] UID %ld, 0x%lx\n",
237
	      (ulong) pair, (ulong) font,
238
	      pair->mxx, pair->mxy, pair->myx, pair->myy,
239
	      (long)pair->UID.id, (ulong) pair->UID.xvalues);
240
    *ppair = pair;
241
    return 0;
242
}
243
 
244
/* Look up the xfont for a font/matrix pair. */
245
/* (This is only exported for gxccache.c.) */
246
void
247
gx_lookup_xfont(const gs_state * pgs, cached_fm_pair * pair, int encoding_index)
248
{
249
    gx_device *dev = gs_currentdevice(pgs);
250
    gx_device *fdev = (*dev_proc(dev, get_xfont_device)) (dev);
251
    gs_font *font = pair->font;
252
    const gx_xfont_procs *procs = (*dev_proc(fdev, get_xfont_procs)) (fdev);
253
    gx_xfont *xf = 0;
254
 
255
    /* We mustn't attempt to use xfonts for stroked characters, */
256
    /* because such characters go outside their bounding box. */
257
    if (procs != 0 && font->PaintType == 0) {
258
	gs_matrix mat;
259
 
260
	mat.xx = pair->mxx, mat.xy = pair->mxy;
261
	mat.yx = pair->myx, mat.yy = pair->myy;
262
	mat.tx = 0, mat.ty = 0;
263
	/* xfonts can outlive their invocations, */
264
	/* but restore purges them properly. */
265
	pair->memory = pgs->memory;
266
	if (font->key_name.size != 0)
267
	    xf = lookup_xfont_by_name(fdev, procs,
268
				      &font->key_name, encoding_index,
269
				      pair, &mat);
270
#define font_name_eq(pfn1,pfn2)\
271
  ((pfn1)->size == (pfn2)->size && (pfn1)->size != 0 &&\
272
   !memcmp((char *)(pfn1)->chars, (char *)(pfn2)->chars, (pfn1)->size))
273
	if (xf == 0 && font->font_name.size != 0 &&
274
	/* Avoid redundant lookup */
275
	    !font_name_eq(&font->font_name, &font->key_name)
276
	    )
277
	    xf = lookup_xfont_by_name(fdev, procs,
278
				      &font->font_name, encoding_index,
279
				      pair, &mat);
280
	if (xf == 0 && font->FontType != ft_composite &&
281
	    uid_is_valid(&((gs_font_base *) font)->UID)
282
	    ) {			/* Look for an original font with the same UID. */
283
	    gs_font_dir *pdir = font->dir;
284
	    gs_font *pfont;
285
 
286
	    for (pfont = pdir->orig_fonts; pfont != 0;
287
		 pfont = pfont->next
288
		) {
289
		if (pfont->FontType != ft_composite &&
290
		    uid_equal(&((gs_font_base *) pfont)->UID,
291
			      &((gs_font_base *) font)->UID) &&
292
		    pfont->key_name.size != 0 &&
293
		    !font_name_eq(&font->key_name,
294
				  &pfont->key_name)
295
		    ) {
296
		    xf = lookup_xfont_by_name(fdev, procs,
297
					      &pfont->key_name,
298
					      encoding_index, pair, &mat);
299
		    if (xf != 0)
300
			break;
301
		}
302
	    }
303
	}
304
    }
305
    pair->xfont = xf;
306
}
307
 
308
/* ------ Internal routines ------ */
309
 
310
/* Purge from the caches all references to a given font/matrix pair, */
311
/* or just characters that depend on its xfont. */
312
#define cpair ((cached_fm_pair *)vpair)
313
private bool
314
purge_fm_pair_char(const gs_memory_t *mem, cached_char * cc, void *vpair)
315
{
316
    return cc_pair(cc) == cpair;
317
}
318
private bool
319
purge_fm_pair_char_xfont(const gs_memory_t *mem, cached_char * cc, void *vpair)
320
{
321
    return cc_pair(cc) == cpair && cpair->xfont == 0 && !cc_has_bits(cc);
322
}
323
#undef cpair
324
void
325
gs_purge_fm_pair(gs_font_dir * dir, cached_fm_pair * pair, int xfont_only)
326
{
327
    if_debug2('k', "[k]purging pair 0x%lx%s\n",
328
	      (ulong) pair, (xfont_only ? " (xfont only)" : ""));
329
    if (pair->xfont != 0) {
330
	(*pair->xfont->common.procs->release) (pair->xfont,
331
					       pair->memory);
332
	pair->xfont_tried = false;
333
	pair->xfont = 0;
334
    }
335
    gx_purge_selected_cached_chars(dir,
336
				   (xfont_only ? purge_fm_pair_char_xfont :
337
				    purge_fm_pair_char),
338
				   pair);
339
    if (pair->ttr)
340
	gx_ttfReader__destroy(pair->ttr);
341
    pair->ttr = 0;
342
    if (pair->ttf)
343
	ttfFont__destroy(pair->ttf, dir);
344
    pair->ttf = 0;
345
    if (!xfont_only) {
346
#ifdef DEBUG
347
	if (pair->num_chars != 0) {
348
	    lprintf1("Error in gs_purge_fm_pair: num_chars =%d\n",
349
		     pair->num_chars);
350
	}
351
#endif
352
	fm_pair_set_free(pair);
353
	dir->fmcache.msize--;
354
    }
355
}
356
 
357
/* Look up an xfont by name. */
358
/* The caller must already have done get_xfont_device to get the proper */
359
/* device to pass as the first argument to lookup_font. */
360
private gx_xfont *
361
lookup_xfont_by_name(gx_device * fdev, const gx_xfont_procs * procs,
362
      gs_font_name * pfstr, int encoding_index, const cached_fm_pair * pair,
363
		     const gs_matrix * pmat)
364
{
365
    gx_xfont *xf;
366
 
367
    if_debug5('k', "[k]lookup xfont %s [%g %g %g %g]\n",
368
	      pfstr->chars, pmat->xx, pmat->xy, pmat->yx, pmat->yy);
369
    xf = (*procs->lookup_font) (fdev,
370
				&pfstr->chars[0], pfstr->size,
371
				encoding_index, &pair->UID,
372
				pmat, pair->memory);
373
    if_debug1('k', "[k]... xfont=0x%lx\n", (ulong) xf);
374
    return xf;
375
}
376
 
377
/* ====== Character-level routines ====== */
378
 
379
/*
380
 * Allocate storage for caching a rendered character with possible
381
 * oversampling and/or alpha.  Return the cached_char if OK, 0 if too big.
382
 * If the character is being oversampled, make the size decision
383
 * on the basis of the final (scaled-down) size.
384
 *
385
 * The iwidth and iheight parameters include scaling up for oversampling
386
 * (multiplication by 1 << pscale->{x,y}.)
387
 * The depth parameter is the final number of alpha bits;
388
 * depth <= x scale * y scale.
389
 * If dev == NULL, this is an xfont-only entry.
390
 * If dev != NULL, set up the memory device(s); in this case, if dev2 is
391
 * not NULL, dev should be an alpha-buffer device with dev2 (an alpha
392
 * device) as target.
393
 */
394
cached_char *
395
gx_alloc_char_bits(gs_font_dir * dir, gx_device_memory * dev,
396
		   gx_device_memory * dev2, ushort iwidth, ushort iheight,
397
		   const gs_log2_scale_point * pscale, int depth)
398
{
399
    int log2_xscale = pscale->x;
400
    int log2_yscale = pscale->y;
401
    int log2_depth = ilog2(depth);
402
    uint nwidth_bits = (iwidth >> log2_xscale) << log2_depth;
403
    ulong isize, icdsize;
404
    uint iraster;
405
    cached_char *cc;
406
    gx_device_memory mdev;
407
    gx_device_memory *pdev = dev;
408
    gx_device_memory *pdev2;
409
 
410
    if (dev == NULL) {
411
	mdev.memory = 0;
412
	mdev.target = 0;
413
	pdev = &mdev;
414
    }
415
    pdev2 = (dev2 == 0 ? pdev : dev2);
416
 
417
    /* Compute the scaled-down bitmap size, and test against */
418
    /* the maximum cachable character size. */
419
 
420
    iraster = bitmap_raster(nwidth_bits);
421
    if (iraster != 0 && iheight >> log2_yscale > dir->ccache.upper / iraster) {
422
	if_debug5('k', "[k]no cache bits: scale=%dx%d, raster/scale=%u, height/scale=%u, upper=%u\n",
423
		  1 << log2_xscale, 1 << log2_yscale,
424
		  iraster, iheight, dir->ccache.upper);
425
	return 0;		/* too big */
426
    }
427
    /* Compute the actual bitmap size(s) and allocate the bits. */
428
    if (dev2 == 0) {
429
	/*
430
	 * Render to a full (possibly oversampled) bitmap; compress
431
	 * (if needed) when done.
432
	 *
433
	 * HACK: Preserve the reference count and retained flag.
434
	 */
435
	rc_header rc;
436
	bool retained = pdev->retained;
437
	gx_device *target = pdev->target;
438
 
439
	rc = pdev->rc;
440
	/* Pass the correct target, but decrement its refct afterwards. */
441
	gs_make_mem_mono_device(pdev, pdev->memory, target);
442
	rc_decrement_only(target, "gx_alloc_char_bits"); /* can't go to 0 */
443
	pdev->rc = rc;
444
	pdev->retained = retained;
445
	pdev->width = iwidth;
446
	pdev->height = iheight;
447
	isize = gdev_mem_bitmap_size(pdev);
448
    } else {
449
	/* Use an alpha-buffer device to compress as we go. */
450
	/* Preserve the reference counts, if any. */
451
	rc_header rc;
452
 
453
	rc = dev2->rc;
454
	gs_make_mem_alpha_device(dev2, dev2->memory, NULL, depth);
455
	dev2->rc = rc;
456
	dev2->width = iwidth >> log2_xscale;
457
	dev2->height = iheight >> log2_yscale;
458
	rc = dev->rc;
459
	gs_make_mem_abuf_device(dev, dev->memory, (gx_device *) dev2,
460
				pscale, depth, 0);
461
	dev->rc = rc;
462
	dev->width = iwidth;
463
	dev->height = 2 << log2_yscale;
464
	isize = gdev_mem_bitmap_size(dev) +
465
	    gdev_mem_bitmap_size(dev2);
466
    }
467
    icdsize = isize + sizeof_cached_char;
468
    cc = alloc_char(dir, icdsize);
469
    if (cc == 0)
470
	return 0;
471
    if_debug4('k', "[k]adding char 0x%lx:%u(%u,%u)\n",
472
	      (ulong) cc, (uint) icdsize, iwidth, iheight);
473
 
474
    /* Fill in the entry. */
475
 
476
    cc_set_depth(cc, depth);
477
    cc->xglyph = gx_no_xglyph;
478
    /* Set the width and height to those of the device. */
479
    /* Note that if we are oversampling without an alpha buffer. */
480
    /* these are not the final unscaled dimensions. */
481
    cc->width = pdev2->width;
482
    cc->height = pdev2->height;
483
    cc->shift = 0;
484
    cc_set_raster(cc, gdev_mem_raster(pdev2));
485
    cc_set_pair_only(cc, 0);	/* not linked in yet */
486
    cc->id = gx_no_bitmap_id;
487
    cc->subpix_origin.x = cc->subpix_origin.y = 0;
488
    cc->linked = false;
489
 
490
    /* Open the cache device(s). */
491
 
492
    if (dev2) {			/* The second device is an alpha device that targets */
493
	/* the real storage for the character. */
494
	byte *bits = cc_bits(cc);
495
	uint bsize = (uint) gdev_mem_bitmap_size(dev2);
496
 
497
	memset(bits, 0, bsize);
498
	dev2->base = bits;
499
	(*dev_proc(dev2, open_device)) ((gx_device *) dev2);
500
	dev->base = bits + bsize;
501
	(*dev_proc(dev, open_device)) ((gx_device *) dev);
502
    } else if (dev)
503
	gx_open_cache_device(dev, cc);
504
 
505
    return cc;
506
}
507
 
508
/* Open the cache device. */
509
void
510
gx_open_cache_device(gx_device_memory * dev, cached_char * cc)
511
{
512
    byte *bits = cc_bits(cc);
513
 
514
    dev->width = cc->width;
515
    dev->height = cc->height;
516
    memset((char *)bits, 0, (uint) gdev_mem_bitmap_size(dev));
517
    dev->base = bits;
518
    (*dev_proc(dev, open_device)) ((gx_device *) dev);	/* initialize */
519
}
520
 
521
/* Remove a character from the cache. */
522
void
523
gx_free_cached_char(gs_font_dir * dir, cached_char * cc)
524
{
525
    char_cache_chunk *cck = cc->chunk;
526
 
527
    dir->ccache.chunks = cck;
528
    dir->ccache.cnext = (byte *) cc - cck->data;
529
    if (cc->linked)
530
	cc_pair(cc)->num_chars--;
531
    if_debug2('k', "[k]freeing char 0x%lx, pair=0x%lx\n",
532
	      (ulong) cc, (ulong) cc_pair(cc));
533
    gx_bits_cache_free((gx_bits_cache *) & dir->ccache, &cc->head, cck);
534
}
535
 
536
/* Add a character to the cache */
537
void
538
gx_add_cached_char(gs_font_dir * dir, gx_device_memory * dev,
539
cached_char * cc, cached_fm_pair * pair, const gs_log2_scale_point * pscale)
540
{
541
    if_debug5('k', "[k]chaining char 0x%lx: pair=0x%lx, glyph=0x%lx, wmode=%d, depth=%d\n",
542
	      (ulong) cc, (ulong) pair, (ulong) cc->code,
543
	      cc->wmode, cc_depth(cc));
544
    if (dev != NULL) {
545
	static const gs_log2_scale_point no_scale =
546
	{0, 0};
547
 
548
	/* Close the device, to flush the alpha buffer if any. */
549
	(*dev_proc(dev, close_device)) ((gx_device *) dev);
550
	gx_add_char_bits(dir, cc,
551
			 (gs_device_is_abuf((gx_device *) dev) ?
552
			  &no_scale : pscale));
553
    }
554
    /* Add the new character to the hash table. */
555
    {
556
	uint chi = chars_head_index(cc->code, pair);
557
 
558
	while (dir->ccache.table[chi &= dir->ccache.table_mask] != 0)
559
	    chi++;
560
	dir->ccache.table[chi] = cc;
561
	if (cc->pair == NULL) {
562
	    /* gx_show_text_retry could reset it when bbox_draw
563
	       discovered an insufficient FontBBox and enlarged it. 
564
	       Glyph raster params could change then. */
565
	    cc->pair = pair;
566
	} else
567
	    assert(cc->pair == pair);
568
	cc->linked = true;
569
	cc_set_pair(cc, pair);
570
	pair->num_chars++;
571
    }
572
}
573
 
574
/* Adjust the bits of a newly-rendered character, by unscaling */
575
/* and compressing or converting to alpha values if necessary. */
576
void
577
gx_add_char_bits(gs_font_dir * dir, cached_char * cc,
578
		 const gs_log2_scale_point * plog2_scale)
579
{
580
    int log2_x = plog2_scale->x, log2_y = plog2_scale->y;
581
    uint raster = cc_raster(cc);
582
    byte *bits = cc_bits(cc);
583
    int depth = cc_depth(cc);
584
    int log2_depth = ilog2(depth);
585
    uint nwidth_bits, nraster;
586
    gs_int_rect bbox;
587
 
588
#ifdef DEBUG
589
    if (cc->width % (1 << log2_x) != 0 ||
590
	cc->height % (1 << log2_y) != 0
591
	) {
592
	lprintf4("size %d,%d not multiple of scale %d,%d!\n",
593
		 cc->width, cc->height,
594
		 1 << log2_x, 1 << log2_y);
595
	cc->width &= -1 << log2_x;
596
	cc->height &= -1 << log2_y;
597
    }
598
#endif
599
 
600
    /*
601
     * Compute the bounding box before compressing.
602
     * We may have to scan more bits, but this is a lot faster than
603
     * compressing the white space.  Note that all bbox values are
604
     * in bits, not pixels.
605
     */
606
 
607
    bits_bounding_box(bits, cc->height, raster, &bbox);
608
 
609
    /*
610
     * If the character was oversampled, compress it now.
611
     * In this case we know that log2_depth <= log2_x.
612
     * If the character was not oversampled, or if we converted
613
     * oversampling to alpha dynamically (using an alpha buffer
614
     * intermediate device), log2_x and log2_y are both zero,
615
     * but in the latter case we may still have depth > 1.
616
     */
617
 
618
    if ((log2_x | log2_y) != 0) {
619
	if_debug5('k', "[k]compressing %dx%d by %dx%d to depth=%d\n",
620
		  cc->width, cc->height, 1 << log2_x, 1 << log2_y,
621
		  depth);
622
	if (gs_debug_c('K'))
623
	    debug_dump_bitmap(bits, raster, cc->height,
624
			      "[K]uncompressed bits");
625
	/* Truncate/round the bbox to a multiple of the scale. */
626
	{
627
	    int scale_x = 1 << log2_x;
628
 
629
	    bbox.p.x &= -scale_x;
630
	    bbox.q.x = (bbox.q.x + scale_x - 1) & -scale_x;
631
	}
632
	{
633
	    int scale_y = 1 << log2_y;
634
 
635
	    bbox.p.y &= -scale_y;
636
	    bbox.q.y = (bbox.q.y + scale_y - 1) & -scale_y;
637
	}
638
	cc->width = (bbox.q.x - bbox.p.x) >> log2_x;
639
	cc->height = (bbox.q.y - bbox.p.y) >> log2_y;
640
	nwidth_bits = cc->width << log2_depth;
641
	nraster = bitmap_raster(nwidth_bits);
642
	bits_compress_scaled(bits + raster * bbox.p.y, bbox.p.x,
643
			     cc->width << log2_x,
644
			     cc->height << log2_y,
645
			     raster,
646
			     bits, nraster, plog2_scale, log2_depth);
647
	bbox.p.x >>= log2_x;
648
	bbox.p.y >>= log2_y;
649
    } else {
650
	/* No oversampling, just remove white space on all 4 sides. */
651
	const byte *from = bits + raster * bbox.p.y + (bbox.p.x >> 3);
652
 
653
	cc->height = bbox.q.y - bbox.p.y;
654
	bbox.p.x &= ~7;		/* adjust to byte boundary */
655
	bbox.p.x >>= log2_depth;	/* bits => pixels */
656
	bbox.q.x = (bbox.q.x + depth - 1) >> log2_depth;	/* ditto */
657
	cc->width = bbox.q.x - bbox.p.x;
658
	nwidth_bits = cc->width << log2_depth;
659
	nraster = bitmap_raster(nwidth_bits);
660
	if (bbox.p.x != 0 || nraster != raster) {
661
	    /* Move the bits down and over. */
662
	    byte *to = bits;
663
	    uint n = cc->height;
664
 
665
	    /* We'd like to move only 
666
	       uint nbytes = (nwidth_bits + 7) >> 3;
667
	       * bytes per scan line, but unfortunately this drops
668
	       * the guaranteed zero padding at the end.
669
	     */
670
 
671
	    for (; n--; from += raster, to += nraster)
672
		memmove(to, from, /*nbytes */ nraster);
673
	} else if (bbox.p.y != 0) {	/* Just move the bits down. */
674
	    memmove(bits, from, raster * cc->height);
675
	}
676
    }
677
 
678
    /* Adjust the offsets to account for removed white space. */
679
 
680
    cc->offset.x -= int2fixed(bbox.p.x);
681
    cc->offset.y -= int2fixed(bbox.p.y);
682
 
683
    /* Discard the memory device overhead that follows the bits, */
684
    /* and any space reclaimed from unscaling or compression. */
685
 
686
    cc_set_raster(cc, nraster);
687
    {
688
	uint diff = ROUND_DOWN(cc->head.size - sizeof_cached_char -
689
			       nraster * cc->height,
690
			       align_cached_char_mod);
691
 
692
	if (diff >= sizeof(cached_char_head)) {
693
	    shorten_cached_char(dir, cc, diff);
694
	    if_debug2('K', "[K]shortening char 0x%lx by %u (adding)\n",
695
		      (ulong) cc, diff);
696
	}
697
    }
698
 
699
    /* Assign a bitmap id. */
700
 
701
    cc->id = gs_next_ids(dir->orig_fonts->memory, 1);
702
}
703
 
704
/* Purge from the caches all references to a given font. */
705
void
706
gs_purge_font_from_char_caches(gs_font_dir * dir, const gs_font * font)
707
{
708
    cached_fm_pair *pair = dir->fmcache.mdata;
709
    int count = dir->fmcache.mmax;
710
 
711
    if_debug1('k', "[k]purging font 0x%lx\n",
712
	      (ulong) font);
713
    while (count--) {
714
	if (pair->font == font) {
715
	    if (uid_is_valid(&pair->UID)) {	/* Keep the entry. */
716
		pair->font = 0;
717
	    } else
718
		gs_purge_fm_pair(dir, pair, 0);
719
	}
720
	pair++;
721
    }
722
}
723
 
724
/* ------ Internal routines ------ */
725
 
726
/* Allocate data space for a cached character, adding a new chunk if needed. */
727
private cached_char *
728
alloc_char(gs_font_dir * dir, ulong icdsize)
729
{				/* Try allocating at the current position first. */
730
    cached_char *cc = alloc_char_in_chunk(dir, icdsize);
731
 
732
    if (cc == 0) {
733
	if (dir->ccache.bspace < dir->ccache.bmax) {	/* Allocate another chunk. */
734
	    gs_memory_t *mem = dir->ccache.bits_memory;
735
	    char_cache_chunk *cck_prev = dir->ccache.chunks;
736
	    char_cache_chunk *cck;
737
	    uint cksize = dir->ccache.bmax / 5 + 1;
738
	    uint tsize = dir->ccache.bmax - dir->ccache.bspace;
739
	    byte *cdata;
740
 
741
	    if (cksize > tsize)
742
		cksize = tsize;
743
	    if (icdsize + sizeof(cached_char_head) > cksize) {
744
		if_debug2('k', "[k]no cache bits: cdsize+head=%lu, cksize=%u\n",
745
			  icdsize + sizeof(cached_char_head),
746
			  cksize);
747
		return 0;	/* wouldn't fit */
748
	    }
749
	    cck = (char_cache_chunk *)
750
		gs_alloc_bytes_immovable(mem, sizeof(*cck),
751
					 "char cache chunk");
752
	    if (cck == 0)
753
		return 0;
754
	    cdata =
755
		gs_alloc_struct_array_immovable(mem, cksize, byte,
756
						&st_font_cache_bytes,
757
						"char cache chunk(data)");
758
	    if (cdata == 0) {
759
		gs_free_object(mem, cck, "char cache chunk");
760
		return 0;
761
	    }
762
	    gx_bits_cache_chunk_init(cck, cdata, cksize);
763
	    cck->next = cck_prev->next;
764
	    cck_prev->next = cck;
765
	    dir->ccache.bspace += cksize;
766
	    dir->ccache.chunks = cck;
767
	} else {		/* Cycle through existing chunks. */
768
	    char_cache_chunk *cck_init = dir->ccache.chunks;
769
	    char_cache_chunk *cck = cck_init;
770
 
771
	    while ((dir->ccache.chunks = cck = cck->next) != cck_init) {
772
		dir->ccache.cnext = 0;
773
		cc = alloc_char_in_chunk(dir, icdsize);
774
		if (cc != 0)
775
		    return cc;
776
	    }
777
	}
778
	dir->ccache.cnext = 0;
779
	cc = alloc_char_in_chunk(dir, icdsize);
780
    }
781
    return cc;
782
}
783
 
784
/* Allocate a character in the current chunk. */
785
private cached_char *
786
alloc_char_in_chunk(gs_font_dir * dir, ulong icdsize)
787
{
788
    char_cache_chunk *cck = dir->ccache.chunks;
789
    cached_char_head *cch;
790
 
791
#define cc ((cached_char *)cch)
792
 
793
    while (gx_bits_cache_alloc((gx_bits_cache *) & dir->ccache,
794
			       icdsize, &cch) < 0
795
	) {
796
	if (cch == 0) {		/* Not enough room to allocate in this chunk. */
797
	    return 0;
798
	} {			/* Free the character */
799
	    cached_fm_pair *pair = cc_pair(cc);
800
 
801
	    if (pair != 0) {
802
		uint chi = chars_head_index(cc->code, pair);
803
 
804
		while (dir->ccache.table[chi & dir->ccache.table_mask] != cc)
805
		    chi++;
806
		hash_remove_cached_char(dir, chi);
807
	    }
808
	    gx_free_cached_char(dir, cc);
809
	}
810
    }
811
    cc->chunk = cck;
812
    cc->loc = (byte *) cc - cck->data;
813
    return cc;
814
#undef cc
815
}
816
 
817
/* Remove the cached_char at a given index in the hash table. */
818
/* In order not to slow down lookup, we relocate following entries. */
819
private void
820
hash_remove_cached_char(gs_font_dir * dir, uint chi)
821
{
822
    uint mask = dir->ccache.table_mask;
823
    uint from = ((chi &= mask) + 1) & mask;
824
    cached_char *cc;
825
 
826
    dir->ccache.table[chi] = 0;
827
    while ((cc = dir->ccache.table[from]) != 0) {	/* Loop invariants: chars[chi] == 0; */
828
	/* chars[chi+1..from] != 0. */
829
	uint fchi = chars_head_index(cc->code, cc_pair(cc));
830
 
831
	/* If chi <= fchi < from, we relocate the character. */
832
	/* Note that '<=' must take wraparound into account. */
833
	if ((chi < from ? chi <= fchi && fchi < from :
834
	     chi <= fchi || fchi < from)
835
	    ) {
836
	    dir->ccache.table[chi] = cc;
837
	    dir->ccache.table[from] = 0;
838
	    chi = from;
839
	}
840
	from = (from + 1) & mask;
841
    }
842
}
843
 
844
/* Shorten a cached character. */
845
/* diff >= sizeof(cached_char_head). */
846
private void
847
shorten_cached_char(gs_font_dir * dir, cached_char * cc, uint diff)
848
{
849
    gx_bits_cache_shorten((gx_bits_cache *) & dir->ccache, &cc->head,
850
			  diff, cc->chunk);
851
    if_debug2('K', "[K]shortening creates free block 0x%lx(%u)\n",
852
	      (ulong) ((byte *) cc + cc->head.size), diff);
853
}