1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Character cache management routines for Ghostscript library */
18 #include "gx.h"
19 #include "memory_.h"
20 #include "gpcheck.h"
21 #include "gserrors.h"
22 #include "gsstruct.h"
23 #include "gsbitops.h"
24 #include "gsutil.h"		/* for gs_next_ids */
25 #include "gxfixed.h"
26 #include "gxmatrix.h"
27 #include "gzstate.h"
28 #include "gxpath.h"
29 #include "gxdevice.h"
30 #include "gxdevmem.h"
31 #include "gxchar.h"
32 #include "gxfont.h"
33 #include "gxfcache.h"
34 #include "gxxfont.h"
35 #include "gxttfb.h"
36 #include "gxfont42.h"
37 
38 /* Define the descriptors for the cache structures. */
39 private_st_cached_fm_pair();
40 private_st_cached_fm_pair_elt();
41 /*private_st_cached_char(); *//* unused */
42 private_st_cached_char_ptr();	/* unused */
43 private_st_cached_char_ptr_elt();
44 /*
45  * Define a descriptor for the cache data.  This is equivalent to st_bytes,
46  * but it identifies the cache data as such in a memory dump.
47  */
48 gs_private_st_simple(st_font_cache_bytes, byte, "font cache bytes");
49 /* GC procedures */
50 /* We do all the work in font_dir_enum/reloc_ptrs in gsfont.c. */
51 /* See gxfcache.h for details. */
52 static
53 ENUM_PTRS_BEGIN(cc_ptr_enum_ptrs) return 0;
54 
55 ENUM_PTRS_END
RELOC_PTRS_BEGIN(cc_ptr_reloc_ptrs)56 static RELOC_PTRS_BEGIN(cc_ptr_reloc_ptrs)
57 {
58 }
59 RELOC_PTRS_END
60 
61 /* Forward references */
62 static int alloc_char(gs_font_dir *, ulong, cached_char **);
63 static int alloc_char_in_chunk(gs_font_dir *, ulong, cached_char **);
64 static void hash_remove_cached_char(gs_font_dir *, uint);
65 static void shorten_cached_char(gs_font_dir *, cached_char *, uint);
66 
67 /* ====== Initialization ====== */
68 
69 /* Allocate and initialize the character cache elements of a font directory. */
70 int
gx_char_cache_alloc(gs_memory_t * struct_mem,gs_memory_t * bits_mem,gs_font_dir * pdir,uint bmax,uint mmax,uint cmax,uint upper)71 gx_char_cache_alloc(gs_memory_t * struct_mem, gs_memory_t * bits_mem,
72             gs_font_dir * pdir, uint bmax, uint mmax, uint cmax, uint upper)
73 {				/* Since we use open hashing, we must increase cmax somewhat. */
74     uint chsize = (cmax + (cmax >> 1)) | 31;
75     cached_fm_pair *mdata;
76     cached_char **chars;
77 
78     /* the table size must be adjusted upward such that we overflow
79        cache character memory before filling the table.  The searching
80        code uses an empty table entry as a sentinel. */
81     chsize = max(chsize, ROUND_UP(bmax, sizeof_cached_char) / sizeof_cached_char + 1);
82 
83     /* Round up chsize to a power of 2. */
84     while (chsize & (chsize + 1))
85         chsize |= chsize >> 1;
86     chsize++;
87     mdata = gs_alloc_struct_array(struct_mem, mmax, cached_fm_pair,
88                                   &st_cached_fm_pair_element,
89                                   "font_dir_alloc(mdata)");
90     chars = gs_alloc_struct_array(struct_mem, chsize, cached_char *,
91                                   &st_cached_char_ptr_element,
92                                   "font_dir_alloc(chars)");
93     if (mdata == 0 || chars == 0) {
94         gs_free_object(struct_mem, chars, "font_dir_alloc(chars)");
95         gs_free_object(struct_mem, mdata, "font_dir_alloc(mdata)");
96         return_error(gs_error_VMerror);
97     }
98     pdir->fmcache.mmax = mmax;
99     pdir->fmcache.mdata = mdata;
100     pdir->ccache.struct_memory = struct_mem;
101     pdir->ccache.bits_memory = bits_mem;
102     pdir->ccache.bmax = bmax;
103     pdir->ccache.cmax = cmax;
104     pdir->ccache.lower = upper / 10;
105     pdir->ccache.upper = upper;
106     pdir->ccache.table = chars;
107     pdir->ccache.table_mask = chsize - 1;
108     gx_char_cache_init(pdir);
109     return 0;
110 }
111 
112 /* Initialize the character cache. */
113 void
gx_char_cache_init(register gs_font_dir * dir)114 gx_char_cache_init(register gs_font_dir * dir)
115 {
116     int i;
117     cached_fm_pair *pair;
118     char_cache_chunk *cck = (char_cache_chunk *)
119     gs_alloc_bytes_immovable(dir->ccache.bits_memory,
120                              sizeof(char_cache_chunk),
121                              "initial_chunk");
122 
123     dir->fmcache.msize = 0;
124     dir->fmcache.used = dir->fmcache.mmax;
125     dir->fmcache.free = dir->fmcache.mmax;
126     dir->fmcache.unused = 0;
127     gx_bits_cache_chunk_init(cck, NULL, 0);
128     gx_bits_cache_init((gx_bits_cache *) & dir->ccache, cck);
129     dir->ccache.bspace = 0;
130     memset((char *)dir->ccache.table, 0,
131            (dir->ccache.table_mask + 1) * sizeof(cached_char *));
132     for (i = 0, pair = dir->fmcache.mdata;
133          i < dir->fmcache.mmax; i++, pair++) {
134         pair->index = i;
135         fm_pair_init(pair);
136         pair->ttf = 0;
137         pair->ttr = 0;
138     }
139 }
140 
141 /* ====== Purging ====== */
142 
143 /* Purge from the character cache all entries selected by */
144 /* a client-supplied procedure. */
145 void
gx_purge_selected_cached_chars(gs_font_dir * dir,bool (* proc)(const gs_memory_t * mem,cached_char *,void *),void * proc_data)146 gx_purge_selected_cached_chars(gs_font_dir * dir,
147                                bool(*proc) (const gs_memory_t *mem,
148                                             cached_char *, void *),
149                                void *proc_data)
150 {
151     int chi;
152     int cmax = dir->ccache.table_mask;
153 
154     for (chi = 0; chi <= cmax;) {
155         cached_char *cc = dir->ccache.table[chi];
156 
157         if (cc != 0 &&
158 #ifdef GSLITE
159                 !cc->dont_evict &&
160 #endif
161                 (*proc) (dir->memory, cc, proc_data)) {
162             hash_remove_cached_char(dir, chi);
163             gx_free_cached_char(dir, cc);
164         } else
165             chi++;
166     }
167 }
168 
169 /* ====== font-matrix pair lists ====== */
170 
171 static int
fm_pair_remove_from_list(gs_font_dir * dir,cached_fm_pair * pair,uint * head)172 fm_pair_remove_from_list(gs_font_dir * dir, cached_fm_pair *pair, uint *head)
173 {
174     if (dir->fmcache.mdata + pair->index != pair)
175         return_error(gs_error_unregistered); /* Must not happen. */
176     if (pair->next == pair->index) {
177         /* The list consists of single element. */
178         if (pair->prev != pair->index)
179             return_error(gs_error_unregistered); /* Must not happen. */
180         *head = dir->fmcache.mmax;
181     } else {
182         cached_fm_pair *next = dir->fmcache.mdata + pair->next;
183         cached_fm_pair *prev = dir->fmcache.mdata + pair->prev;
184 
185         if (next->prev != pair->index)
186             return_error(gs_error_unregistered); /* Must not happen. */
187         if (prev->next != pair->index)
188             return_error(gs_error_unregistered); /* Must not happen. */
189         if (*head == pair->index)
190             *head = next->index;
191         next->prev = prev->index;
192         prev->next = next->index;
193     }
194     return 0;
195 }
196 
197 static int
fm_pair_insert_into_list(gs_font_dir * dir,cached_fm_pair * pair,uint * head)198 fm_pair_insert_into_list(gs_font_dir * dir, cached_fm_pair *pair, uint *head)
199 {
200     if (dir->fmcache.mdata + pair->index != pair)
201         return_error(gs_error_unregistered); /* Must not happen. */
202     if (*head >= dir->fmcache.mmax) {
203         *head = pair->next = pair->prev = pair->index;
204     } else {
205         cached_fm_pair *first = dir->fmcache.mdata + *head;
206         cached_fm_pair *last = dir->fmcache.mdata + first->prev;
207 
208         if (first->prev != last->index)
209             return_error(gs_error_unregistered); /* Must not happen. */
210         if (last->next != first->index)
211             return_error(gs_error_unregistered); /* Must not happen. */
212         pair->next = first->index;
213         pair->prev = last->index;
214         first->prev = last->next = pair->index;
215         *head = pair->index;
216     }
217     return 0;
218 }
219 
220 /* ====== Font-level routines ====== */
221 
222 static int
gx_attach_tt_interpreter(gs_font_dir * dir,gs_font_type42 * font,cached_fm_pair * pair,const gs_matrix * char_tm,const gs_log2_scale_point * log2_scale,bool design_grid)223 gx_attach_tt_interpreter(gs_font_dir * dir,
224                gs_font_type42 *font, cached_fm_pair *pair,
225                const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
226                bool design_grid)
227 {
228     float cxx, cxy, cyx, cyy;
229     gs_matrix m;
230     int code;
231 
232     gx_compute_char_matrix(char_tm, log2_scale, &cxx, &cxy, &cyx, &cyy);
233     pair->design_grid = design_grid;
234     m.xx = cxx;
235     m.xy = cxy;
236     m.yx = cyx;
237     m.yy = cyy;
238     m.tx = m.ty = 0;
239     pair->ttr = gx_ttfReader__create(dir->memory->stable_memory);
240     if (!pair->ttr)
241         return_error(gs_error_VMerror);
242     /*  We could use a single the reader instance for all fonts ... */
243     pair->ttf = ttfFont__create(dir);
244     if (!pair->ttf)
245         return_error(gs_error_VMerror);
246     gx_ttfReader__set_font(pair->ttr, (gs_font_type42 *)font);
247     code = ttfFont__Open_aux(pair->ttf, dir->tti, pair->ttr,
248                 (gs_font_type42 *)font, &m, log2_scale, design_grid);
249     gx_ttfReader__set_font(pair->ttr, NULL);
250     return code;
251 }
252 
253 static inline bool
does_font_need_tt_interpreter(gs_font * font)254 does_font_need_tt_interpreter(gs_font *font)
255 {
256     if (font->FontType == ft_TrueType || font->FontType == ft_CID_TrueType) {
257         gs_font_type42 *pfont = (gs_font_type42 *)font;
258 
259         if (pfont->FAPI==NULL)
260             return true;
261     }
262     return false;
263 }
264 
265 int
gx_provide_fm_pair_attributes(gs_font_dir * dir,gs_font * font,cached_fm_pair * pair,const gs_matrix * char_tm,const gs_log2_scale_point * log2_scale,bool design_grid)266 gx_provide_fm_pair_attributes(gs_font_dir * dir,
267                gs_font *font, cached_fm_pair *pair,
268                const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
269                bool design_grid)
270 {
271     if (does_font_need_tt_interpreter(font)) {
272         if (pair->ttf != NULL)
273             return 0; /* Already attached. */
274         return gx_attach_tt_interpreter(dir, (gs_font_type42 *)font, pair,
275                         char_tm, log2_scale, design_grid);
276     }
277     return 0;
278 }
279 
280 /* Add a font/matrix pair to the cache. */
281 /* (This is only exported for gxccache.c.) */
282 int
gx_add_fm_pair(register gs_font_dir * dir,gs_font * font,const gs_uid * puid,const gs_matrix * char_tm,const gs_log2_scale_point * log2_scale,bool design_grid,cached_fm_pair ** ppair)283 gx_add_fm_pair(register gs_font_dir * dir, gs_font * font, const gs_uid * puid,
284                const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
285                bool design_grid, cached_fm_pair **ppair)
286 {
287     float mxx, mxy, myx, myy;
288     register cached_fm_pair *pair;
289     int code;
290 
291     gx_compute_ccache_key(font, char_tm, log2_scale, design_grid,
292                             &mxx, &mxy, &myx, &myy);
293     if (dir->fmcache.msize == dir->fmcache.mmax) {
294         /* cache is full, drop the older entry. */
295         /* gx_touch_fm_pair must be called whenever
296            a pair is used to move it to the top of the list.
297            Since we drop a pair from the list bottom,
298            and since the list is long enough,
299            with a high probability it won't drop a pair,
300            which currently is pointed by an active text enumerator.
301 
302            Note that with Type 3 fonts multiple text enumerators
303            may be active (exist on estack) in same time,
304            therefore the list length sets a constraint for
305            the number of font-matrix pairs used within a charproc.
306            If it uses too many ones, the outer text enumerator
307            will fail with 'invalidfont' in gx_add_cached_char.
308         */
309         pair = dir->fmcache.mdata + dir->fmcache.used;
310         pair = dir->fmcache.mdata + pair->prev; /* last touched. */
311         code = gs_purge_fm_pair(dir, pair, 0);
312         if (code < 0)
313             return code;
314     }
315     if (dir->fmcache.free < dir->fmcache.mmax) {
316         /* use a free entry. */
317         pair = dir->fmcache.mdata + dir->fmcache.free;
318         code = fm_pair_remove_from_list(dir, pair, &dir->fmcache.free);
319         if (code < 0)
320             return code;
321     } else {
322         /* reserve a new entry. */
323         pair = dir->fmcache.mdata + dir->fmcache.unused;
324         dir->fmcache.unused++;
325     }
326     font->is_cached = true; /* Set this early to ensure
327             gs_purge_font_from_char_caches works for it in case of errors. */
328     dir->fmcache.msize++;
329     code = fm_pair_insert_into_list(dir, pair, &dir->fmcache.used);
330     if (code < 0)
331         return code;
332     pair->font = font;
333     pair->UID = *puid;
334     /* Copy UID into a stable memory,
335        so that 'restore' may keep this pair. */
336     code = uid_copy(&pair->UID, dir->memory->stable_memory, "gx_add_fm_pair");
337     if (code < 0) {
338         uid_set_invalid(&pair->UID);
339         return code;
340     }
341     pair->FontType = font->FontType;
342     pair->hash = (uint) (dir->hash % 549);	/* scramble bits */
343     dir->hash += 371;
344     pair->mxx = mxx, pair->mxy = mxy;
345     pair->myx = myx, pair->myy = myy;
346     pair->num_chars = 0;
347     pair->xfont_tried = false;
348     pair->xfont = 0;
349     pair->ttf = 0;
350     pair->ttr = 0;
351     pair->design_grid = false;
352     if (does_font_need_tt_interpreter(font)) {
353             code = gx_attach_tt_interpreter(dir, (gs_font_type42 *)font, pair,
354                                 char_tm, log2_scale, design_grid);
355             if (code < 0)
356                 return code;
357         }
358     pair->memory = 0;
359     if_debug8('k', "[k]adding pair 0x%lx: font=0x%lx [%g %g %g %g] UID %ld, 0x%lx\n",
360               (ulong) pair, (ulong) font,
361               pair->mxx, pair->mxy, pair->myx, pair->myy,
362               (long)pair->UID.id, (ulong) pair->UID.xvalues);
363     *ppair = pair;
364     return 0;
365 }
366 
367 /* Update the pointer to the last used font/matrix pair. */
368 int
gx_touch_fm_pair(gs_font_dir * dir,cached_fm_pair * pair)369 gx_touch_fm_pair(gs_font_dir *dir, cached_fm_pair *pair)
370 {
371     if (pair->index != dir->fmcache.used) {
372         int code;
373 
374         code = fm_pair_remove_from_list(dir, pair, &dir->fmcache.used);
375         if (code < 0)
376             return code;
377         return fm_pair_insert_into_list(dir, pair, &dir->fmcache.used);
378     }
379     return 0;
380 }
381 
382 /* ------ Internal routines ------ */
383 
384 /* Purge from the caches all references to a given font/matrix pair, */
385 /* or just characters that depend on its xfont. */
386 #define cpair ((cached_fm_pair *)vpair)
387 static bool
purge_fm_pair_char(const gs_memory_t * mem,cached_char * cc,void * vpair)388 purge_fm_pair_char(const gs_memory_t *mem, cached_char * cc, void *vpair)
389 {
390     return cc_pair(cc) == cpair;
391 }
392 #undef cpair
393 
394 static inline void
gs_clean_fm_pair_attributes(gs_font_dir * dir,cached_fm_pair * pair)395 gs_clean_fm_pair_attributes(gs_font_dir * dir, cached_fm_pair * pair)
396 {
397     if (pair->ttr)
398         gx_ttfReader__destroy(pair->ttr);
399     pair->ttr = 0;
400     if (pair->ttf)
401         ttfFont__destroy(pair->ttf, dir);
402     pair->ttf = 0;
403 }
404 
405 void
gs_clean_fm_pair(gs_font_dir * dir,cached_fm_pair * pair)406 gs_clean_fm_pair(gs_font_dir * dir, cached_fm_pair * pair)
407 {
408     if_debug1('k', "[k]cleaning pair 0x%lx\n", (ulong) pair);
409     pair->font = NULL;
410     gs_clean_fm_pair_attributes(dir, pair);
411 }
412 
413 int
gs_purge_fm_pair(gs_font_dir * dir,cached_fm_pair * pair,int xfont_only)414 gs_purge_fm_pair(gs_font_dir * dir, cached_fm_pair * pair, int xfont_only)
415 {
416     if_debug2('k', "[k]purging pair 0x%lx%s\n",
417               (ulong) pair, (xfont_only ? " (xfont only)" : ""));
418     if (pair->xfont != 0) {
419         (*pair->xfont->common.procs->release) (pair->xfont,
420                                                pair->memory);
421         pair->xfont_tried = false;
422         pair->xfont = 0;
423     }
424     gx_purge_selected_cached_chars(dir,
425                                     purge_fm_pair_char,
426                                    pair);
427     gs_clean_fm_pair_attributes(dir, pair);
428     if (!xfont_only) {
429         int code;
430 
431 #ifdef DEBUG
432         if (pair->num_chars != 0) {
433             lprintf1("Error in gs_purge_fm_pair: num_chars =%d\n",
434                      pair->num_chars);
435         }
436 #endif
437         {   /* Free xvalues here because gx_add_fm_pair copied
438                them into the stable memory dir->memory. */
439             gs_free_object(dir->memory->stable_memory, pair->UID.xvalues, "gs_purge_fm_pair");
440             pair->UID.xvalues = 0;
441         }
442         fm_pair_set_free(pair);
443         code = fm_pair_remove_from_list(dir, pair, &dir->fmcache.used);
444         if (code < 0)
445             return code;
446         code = fm_pair_insert_into_list(dir, pair, &dir->fmcache.free);
447         if (code < 0)
448             return code;
449         dir->fmcache.msize--;
450     }
451     return 0;
452 }
453 
454 
455 /* ====== Character-level routines ====== */
456 
457 /*
458  * Allocate storage for caching a rendered character with possible
459  * oversampling and/or alpha.  Return the cached_char if OK, 0 if too big.
460  * If the character is being oversampled, make the size decision
461  * on the basis of the final (scaled-down) size.
462  *
463  * The iwidth and iheight parameters include scaling up for oversampling
464  * (multiplication by 1 << pscale->{x,y}.)
465  * The depth parameter is the final number of alpha bits;
466  * depth <= x scale * y scale.
467  * If dev == NULL, this is an xfont-only entry.
468  * If dev != NULL, set up the memory device(s); in this case, if dev2 is
469  * not NULL, dev should be an alpha-buffer device with dev2 (an alpha
470  * device) as target.
471  */
472 int
gx_alloc_char_bits(gs_font_dir * dir,gx_device_memory * dev,gx_device_memory * dev2,ushort iwidth,ushort iheight,const gs_log2_scale_point * pscale,int depth,cached_char ** pcc)473 gx_alloc_char_bits(gs_font_dir * dir, gx_device_memory * dev,
474                    gx_device_memory * dev2, ushort iwidth, ushort iheight,
475                    const gs_log2_scale_point * pscale, int depth, cached_char **pcc)
476 {
477     int log2_xscale = pscale->x;
478     int log2_yscale = pscale->y;
479     int log2_depth = ilog2(depth);
480     uint nwidth_bits = (iwidth >> log2_xscale) << log2_depth;
481     ulong isize, icdsize, isize2;
482     uint iraster;
483     cached_char *cc;
484     gx_device_memory mdev;
485     gx_device_memory *pdev = dev;
486     gx_device_memory *pdev2;
487     float HWResolution0 = 72, HWResolution1 = 72;  /* default for dev == NULL */
488     int code;
489 
490     *pcc = 0;
491     if (dev == NULL) {
492         mdev.memory = 0;
493         mdev.target = 0;
494         pdev = &mdev;
495     } else {
496         HWResolution0 = dev->HWResolution[0];
497         HWResolution1 = dev->HWResolution[1];
498     }
499 
500     pdev2 = (dev2 == 0 ? pdev : dev2);
501 
502     /* Compute the scaled-down bitmap size, and test against */
503     /* the maximum cachable character size. */
504 
505     iraster = bitmap_raster(nwidth_bits);
506     if (iraster != 0 && iheight >> log2_yscale > dir->ccache.upper / iraster) {
507         if_debug5('k', "[k]no cache bits: scale=%dx%d, raster/scale=%u, height/scale=%u, upper=%u\n",
508                   1 << log2_xscale, 1 << log2_yscale,
509                   iraster, iheight, dir->ccache.upper);
510         return 0;		/* too big */
511     }
512     /* Compute the actual bitmap size(s) and allocate the bits. */
513     if (dev2 == 0) {
514         /*
515          * Render to a full (possibly oversampled) bitmap; compress
516          * (if needed) when done.
517          *
518          * HACK: Preserve the reference count and retained flag.
519          */
520         rc_header rc;
521         bool retained = pdev->retained;
522         gx_device *target = pdev->target;
523 
524         rc = pdev->rc;
525         /* Pass the correct target, but decrement its refct afterwards. */
526         gs_make_mem_mono_device(pdev, pdev->memory, target);
527         rc_decrement_only(target, "gx_alloc_char_bits"); /* can't go to 0 */
528         pdev->rc = rc;
529         pdev->retained = retained;
530         pdev->width = iwidth;
531         pdev->height = iheight;
532         gdev_mem_bitmap_size(pdev, &isize);	/* Assume less than max_ulong */
533         pdev->HWResolution[0] = HWResolution0;
534         pdev->HWResolution[1] = HWResolution1;
535     } else {
536         /* Use an alpha-buffer device to compress as we go. */
537         /* Preserve the reference counts, if any. */
538         rc_header rc;
539 
540         rc = dev2->rc;
541         gs_make_mem_alpha_device(dev2, dev2->memory, NULL, depth);
542         dev2->rc = rc;
543         dev2->width = iwidth >> log2_xscale;
544         dev2->height = iheight >> log2_yscale;
545         rc = dev->rc;
546         gs_make_mem_abuf_device(dev, dev->memory, (gx_device *) dev2,
547                                 pscale, depth, 0, false);
548         dev->rc = rc;
549         dev->width = iwidth;
550         dev->height = 2 << log2_yscale;
551         gdev_mem_bitmap_size(dev, &isize);	/* Assume less than max_ulong */
552         gdev_mem_bitmap_size(dev2, &isize2);	/* Assume less than max_ulong */
553         isize += isize2;	/* Assume less than max_ulong */
554         dev->HWResolution[0] = HWResolution0 * (1 >> log2_xscale);
555         dev->HWResolution[1] = HWResolution1 * (1 >> log2_yscale);
556     }
557     icdsize = isize + sizeof_cached_char;
558     code = alloc_char(dir, icdsize, &cc);
559     if (code < 0)
560         return code;
561     *pcc = cc;
562     if (cc == 0)
563         return 0;
564     if_debug4('k', "[k]adding char 0x%lx:%u(%u,%u)\n",
565               (ulong) cc, (uint) icdsize, iwidth, iheight);
566 
567     /* Fill in the entry. */
568 
569     cc_set_depth(cc, depth);
570     cc->xglyph = gx_no_xglyph;
571     /* Set the width and height to those of the device. */
572     /* Note that if we are oversampling without an alpha buffer. */
573     /* these are not the final unscaled dimensions. */
574     cc->width = pdev2->width;
575     cc->height = pdev2->height;
576     cc->shift = 0;
577     cc_set_raster(cc, gdev_mem_raster(pdev2));
578     cc_set_pair_only(cc, 0);	/* not linked in yet */
579     cc->id = gx_no_bitmap_id;
580     cc->subpix_origin.x = cc->subpix_origin.y = 0;
581     cc->linked = false;
582 
583     /* Open the cache device(s). */
584 
585     if (dev2) {			/* The second device is an alpha device that targets */
586         /* the real storage for the character. */
587         byte *bits = cc_bits(cc);
588         ulong bsize;
589 
590         gdev_mem_bitmap_size(dev2, &bsize);
591         memset(bits, 0, bsize);
592         dev2->base = bits;
593         (*dev_proc(dev2, open_device)) ((gx_device *) dev2);
594         dev->base = bits + bsize;
595         (*dev_proc(dev, open_device)) ((gx_device *) dev);
596     } else if (dev)
597         gx_open_cache_device(dev, cc);
598 
599     return 0;
600 }
601 
602 /* Open the cache device. */
603 void
gx_open_cache_device(gx_device_memory * dev,cached_char * cc)604 gx_open_cache_device(gx_device_memory * dev, cached_char * cc)
605 {
606     byte *bits = cc_bits(cc);
607     ulong bsize;
608 
609     gdev_mem_bitmap_size(dev, &bsize);
610 
611     dev->width = cc->width;
612     dev->height = cc->height;
613     memset((char *)bits, 0, bsize);
614     dev->base = bits;
615     (*dev_proc(dev, open_device)) ((gx_device *) dev);	/* initialize */
616 }
617 
618 /* Remove a character from the cache. */
619 void
gx_free_cached_char(gs_font_dir * dir,cached_char * cc)620 gx_free_cached_char(gs_font_dir * dir, cached_char * cc)
621 {
622     char_cache_chunk *cck = cc->chunk;
623 
624     dir->ccache.chunks = cck;
625     dir->ccache.cnext = (byte *) cc - cck->data;
626     if (cc->linked)
627         cc_pair(cc)->num_chars--;
628     if_debug2('k', "[k]freeing char 0x%lx, pair=0x%lx\n",
629               (ulong) cc, (ulong) cc_pair(cc));
630     gx_bits_cache_free((gx_bits_cache *) & dir->ccache, &cc->head, cck);
631 }
632 
633 /* Add a character to the cache */
634 int
gx_add_cached_char(gs_font_dir * dir,gx_device_memory * dev,cached_char * cc,cached_fm_pair * pair,const gs_log2_scale_point * pscale)635 gx_add_cached_char(gs_font_dir * dir, gx_device_memory * dev,
636 cached_char * cc, cached_fm_pair * pair, const gs_log2_scale_point * pscale)
637 {
638     if_debug5('k', "[k]chaining char 0x%lx: pair=0x%lx, glyph=0x%lx, wmode=%d, depth=%d\n",
639               (ulong) cc, (ulong) pair, (ulong) cc->code,
640               cc->wmode, cc_depth(cc));
641     if (dev != NULL) {
642         static const gs_log2_scale_point no_scale =
643         {0, 0};
644 
645         /* Close the device, to flush the alpha buffer if any. */
646         (*dev_proc(dev, close_device)) ((gx_device *) dev);
647         gx_add_char_bits(dir, cc,
648                          (gs_device_is_abuf((gx_device *) dev) ?
649                           &no_scale : pscale));
650     }
651     /* Add the new character to the hash table. */
652     {
653         uint chi = chars_head_index(cc->code, pair);
654 
655         while (dir->ccache.table[chi &= dir->ccache.table_mask] != 0)
656             chi++;
657         dir->ccache.table[chi] = cc;
658         if (cc->pair == NULL) {
659             /* gx_show_text_retry could reset it when bbox_draw
660                discovered an insufficient FontBBox and enlarged it.
661                Glyph raster params could change then. */
662             cc->pair = pair;
663         } else if (cc->pair != pair) {
664             /* gx_add_fm_pair could drop the active font-matrix pair
665                due to cache overflow during a charproc interpretation.
666                Likely a single charproc renders too many characters
667                for generating the character image.
668                We have no mechanizm for locking font-matrix pairs in cache
669                to avoud their dissipation. Therefore we consider this failure
670                as an implementation limitation. */
671             return_error(gs_error_invalidfont);
672         }
673         cc->linked = true;
674         cc_set_pair(cc, pair);
675         pair->num_chars++;
676     }
677     return 0;
678 }
679 
680 /* Adjust the bits of a newly-rendered character, by unscaling */
681 /* and compressing or converting to alpha values if necessary. */
682 void
gx_add_char_bits(gs_font_dir * dir,cached_char * cc,const gs_log2_scale_point * plog2_scale)683 gx_add_char_bits(gs_font_dir * dir, cached_char * cc,
684                  const gs_log2_scale_point * plog2_scale)
685 {
686     int log2_x = plog2_scale->x, log2_y = plog2_scale->y;
687     uint raster = cc_raster(cc);
688     byte *bits = cc_bits(cc);
689     int depth = cc_depth(cc);
690     int log2_depth = ilog2(depth);
691     uint nwidth_bits, nraster;
692     gs_int_rect bbox;
693 
694 #ifdef DEBUG
695     if (cc->width % (1 << log2_x) != 0 ||
696         cc->height % (1 << log2_y) != 0
697         ) {
698         lprintf4("size %d,%d not multiple of scale %d,%d!\n",
699                  cc->width, cc->height,
700                  1 << log2_x, 1 << log2_y);
701         cc->width &= -1 << log2_x;
702         cc->height &= -1 << log2_y;
703     }
704 #endif
705 
706     /*
707      * Compute the bounding box before compressing.
708      * We may have to scan more bits, but this is a lot faster than
709      * compressing the white space.  Note that all bbox values are
710      * in bits, not pixels.
711      */
712 
713     bits_bounding_box(bits, cc->height, raster, &bbox);
714 
715     /*
716      * If the character was oversampled, compress it now.
717      * In this case we know that log2_depth <= log2_x.
718      * If the character was not oversampled, or if we converted
719      * oversampling to alpha dynamically (using an alpha buffer
720      * intermediate device), log2_x and log2_y are both zero,
721      * but in the latter case we may still have depth > 1.
722      */
723 
724     if ((log2_x | log2_y) != 0) {
725         if_debug5('k', "[k]compressing %dx%d by %dx%d to depth=%d\n",
726                   cc->width, cc->height, 1 << log2_x, 1 << log2_y,
727                   depth);
728 #ifdef DEBUG
729         if (gs_debug_c('K'))
730             debug_dump_bitmap(bits, raster, cc->height,
731                               "[K]uncompressed bits");
732 #endif
733         /* Truncate/round the bbox to a multiple of the scale. */
734         {
735             int scale_x = 1 << log2_x;
736 
737             bbox.p.x &= -scale_x;
738             bbox.q.x = (bbox.q.x + scale_x - 1) & -scale_x;
739         }
740         {
741             int scale_y = 1 << log2_y;
742 
743             bbox.p.y &= -scale_y;
744             bbox.q.y = (bbox.q.y + scale_y - 1) & -scale_y;
745         }
746         cc->width = (bbox.q.x - bbox.p.x) >> log2_x;
747         cc->height = (bbox.q.y - bbox.p.y) >> log2_y;
748         nwidth_bits = cc->width << log2_depth;
749         nraster = bitmap_raster(nwidth_bits);
750         bits_compress_scaled(bits + raster * bbox.p.y, bbox.p.x,
751                              cc->width << log2_x,
752                              cc->height << log2_y,
753                              raster,
754                              bits, nraster, plog2_scale, log2_depth);
755         bbox.p.x >>= log2_x;
756         bbox.p.y >>= log2_y;
757     } else {
758         /* No oversampling, just remove white space on all 4 sides. */
759         const byte *from = bits + raster * bbox.p.y + (bbox.p.x >> 3);
760 
761         cc->height = bbox.q.y - bbox.p.y;
762         bbox.p.x &= ~7;		/* adjust to byte boundary */
763         bbox.p.x >>= log2_depth;	/* bits => pixels */
764         bbox.q.x = (bbox.q.x + depth - 1) >> log2_depth;	/* ditto */
765         cc->width = bbox.q.x - bbox.p.x;
766         nwidth_bits = cc->width << log2_depth;
767         nraster = bitmap_raster(nwidth_bits);
768         if (bbox.p.x != 0 || nraster != raster) {
769             /* Move the bits down and over. */
770             byte *to = bits;
771             uint n = cc->height;
772 
773             /* We'd like to move only
774                uint nbytes = (nwidth_bits + 7) >> 3;
775                * bytes per scan line, but unfortunately this drops
776                * the guaranteed zero padding at the end.
777              */
778 
779             for (; n--; from += raster, to += nraster)
780                 memmove(to, from, /*nbytes */ nraster);
781         } else if (bbox.p.y != 0) {	/* Just move the bits down. */
782             memmove(bits, from, raster * cc->height);
783         }
784     }
785 
786     /* Adjust the offsets to account for removed white space. */
787 
788     cc->offset.x -= int2fixed(bbox.p.x);
789     cc->offset.y -= int2fixed(bbox.p.y);
790 
791     /* Discard the memory device overhead that follows the bits, */
792     /* and any space reclaimed from unscaling or compression. */
793 
794     cc_set_raster(cc, nraster);
795     {
796         uint diff = ROUND_DOWN(cc->head.size - sizeof_cached_char -
797                                nraster * cc->height,
798                                align_cached_char_mod);
799 
800         if (diff >= sizeof(cached_char_head)) {
801             shorten_cached_char(dir, cc, diff);
802             if_debug2('K', "[K]shortening char 0x%lx by %u (adding)\n",
803                       (ulong) cc, diff);
804         }
805     }
806 
807     /* Assign a bitmap id. */
808 
809     cc->id = gs_next_ids(dir->memory, 1);
810 }
811 
812 /* Purge from the caches all references to a given font. */
813 static int
gs_purge_font_from_char_caches_forced(gs_font * font,bool force)814 gs_purge_font_from_char_caches_forced(gs_font * font, bool force)
815 {
816     gs_font_dir * dir;
817     cached_fm_pair *pair;
818     int count;
819 
820     if (font->dir == NULL)
821         return 0; /* The font was not properly build due to errors. */
822     if (!font->is_cached)
823         return 0;
824     dir = font->dir;
825     pair = dir->fmcache.mdata;
826     count = dir->fmcache.mmax;
827     font->is_cached = false; /* Prevent redundant execution. */
828     if_debug1('k', "[k]purging font 0x%lx\n",
829               (ulong) font);
830     for (; count--; pair++) {
831         if (pair->font == font) {
832             if (!force && uid_is_valid(&pair->UID)) {	/* Keep the entry. */
833                 gs_clean_fm_pair(dir, pair);
834             } else {
835                 int code = gs_purge_fm_pair(dir, pair, 0);
836 
837                 if (code < 0)
838                     return code;
839             }
840         }
841     }
842     return 0;
843 }
844 
845 /* Purge from the caches all references to a given font,
846    with leaving persistent chars in the cache. */
847 int
gs_purge_font_from_char_caches(gs_font * font)848 gs_purge_font_from_char_caches(gs_font * font)
849 {
850     /* This function is called when a font is being released.
851        The purpose is to remove all cache attributes,
852        which may point to the font data.
853        Note : when a font has a valid XUID,
854        it doesn't release cache entries and cached chars,
855        so that they may be used in future
856        if a font with same XUID appears again.
857        All this improves the performance when
858        a document executes a sequence like this :
859 
860        n {
861           save /fontname findfont 10 scalefont
862           (xyz) show
863           restore
864        } repeat
865      */
866     return gs_purge_font_from_char_caches_forced(font, false);
867 }
868 
869 /* Purge from the caches all references to a given font,
870    without leaving persistent chars in the cache. */
871 int
gs_purge_font_from_char_caches_completely(gs_font * font)872 gs_purge_font_from_char_caches_completely(gs_font * font)
873 {
874     /* A client should call this finction
875        when it frees a font,
876        and the client doesn't need to leave
877        persistent cache entries for this font
878        even if the font has a valid XUID.
879      */
880     return gs_purge_font_from_char_caches_forced(font, true);
881 }
882 
883 /* ------ Internal routines ------ */
884 
885 /* Allocate data space for a cached character, adding a new chunk if needed. */
886 static int
alloc_char(gs_font_dir * dir,ulong icdsize,cached_char ** pcc)887 alloc_char(gs_font_dir * dir, ulong icdsize, cached_char **pcc)
888 {				/* Try allocating at the current position first. */
889     cached_char *cc;
890     int code = alloc_char_in_chunk(dir, icdsize, &cc);
891 
892     *pcc = cc;
893     if (code < 0)
894         return code;
895     if (cc == 0) {
896         if (dir->ccache.bspace < dir->ccache.bmax) {	/* Allocate another chunk. */
897             gs_memory_t *mem = dir->ccache.bits_memory;
898             char_cache_chunk *cck_prev = dir->ccache.chunks;
899             char_cache_chunk *cck;
900             uint cksize = dir->ccache.bmax / 5 + 1;
901             uint tsize = dir->ccache.bmax - dir->ccache.bspace;
902             byte *cdata;
903 
904             if (cksize > tsize)
905                 cksize = tsize;
906             if (icdsize + sizeof(cached_char_head) > cksize) {
907                 if_debug2('k', "[k]no cache bits: cdsize+head=%lu, cksize=%u\n",
908                           icdsize + sizeof(cached_char_head),
909                           cksize);
910                 return 0;	/* wouldn't fit */
911             }
912             cck = (char_cache_chunk *)
913                 gs_alloc_bytes_immovable(mem, sizeof(*cck),
914                                          "char cache chunk");
915             if (cck == 0)
916                 return 0;
917             cdata =
918                 gs_alloc_struct_array_immovable(mem, cksize, byte,
919                                                 &st_font_cache_bytes,
920                                                 "char cache chunk(data)");
921             if (cdata == 0) {
922                 gs_free_object(mem, cck, "char cache chunk");
923                 return 0;
924             }
925             gx_bits_cache_chunk_init(cck, cdata, cksize);
926             cck->next = cck_prev->next;
927             cck_prev->next = cck;
928             dir->ccache.bspace += cksize;
929             dir->ccache.chunks = cck;
930         } else {		/* Cycle through existing chunks. */
931             char_cache_chunk *cck_init = dir->ccache.chunks;
932             char_cache_chunk *cck = cck_init;
933 
934             while ((dir->ccache.chunks = cck = cck->next) != cck_init) {
935                 dir->ccache.cnext = 0;
936                 code = alloc_char_in_chunk(dir, icdsize, &cc);
937                 if (code < 0)
938                     return code;
939                 if (cc != 0) {
940                     *pcc = cc;
941                     return 0;
942                 }
943             }
944         }
945         dir->ccache.cnext = 0;
946         code = alloc_char_in_chunk(dir, icdsize, &cc);
947         if (code < 0)
948             return code;
949         *pcc = cc;
950     }
951     return 0;
952 }
953 
954 /* Allocate a character in the current chunk. */
955 static int
alloc_char_in_chunk(gs_font_dir * dir,ulong icdsize,cached_char ** pcc)956 alloc_char_in_chunk(gs_font_dir * dir, ulong icdsize, cached_char **pcc)
957 {
958     char_cache_chunk *cck = dir->ccache.chunks;
959     cached_char_head *cch;
960 
961 #define cc ((cached_char *)cch)
962 
963     *pcc = 0;
964     while (gx_bits_cache_alloc((gx_bits_cache *) & dir->ccache,
965                                icdsize, &cch) < 0
966         ) {
967         if (cch == 0) {		/* Not enough room to allocate in this chunk. */
968             return 0;
969         }
970 #ifdef GSLITE
971         /* We shouldn't free because it's used. */
972         if (cc->dont_evict) {
973             return 0;
974         }
975 #endif
976         else {			/* Free the character */
977             cached_fm_pair *pair = cc_pair(cc);
978 
979             if (pair != 0) {
980                 uint chi = chars_head_index(cc->code, pair);
981                 uint cnt = dir->ccache.table_mask + 1;
982 
983                 while (dir->ccache.table[chi & dir->ccache.table_mask] != cc) {
984                     chi++;
985                     if (cnt-- == 0)
986                         return_error(gs_error_unregistered); /* Must not happen. */
987                 }
988                 hash_remove_cached_char(dir, chi);
989             }
990 
991             gx_free_cached_char(dir, cc);
992         }
993     }
994 
995 #ifdef GSLITE
996     cc->dont_evict = 0;
997 #endif
998 
999     cc->chunk = cck;
1000     cc->loc = (byte *) cc - cck->data;
1001     *pcc = cc;
1002     return 0;
1003 
1004 #undef cc
1005 }
1006 
1007 /* Remove the cached_char at a given index in the hash table. */
1008 /* In order not to slow down lookup, we relocate following entries. */
1009 static void
hash_remove_cached_char(gs_font_dir * dir,uint chi)1010 hash_remove_cached_char(gs_font_dir * dir, uint chi)
1011 {
1012     uint mask = dir->ccache.table_mask;
1013     uint from = ((chi &= mask) + 1) & mask;
1014     cached_char *cc;
1015 
1016     dir->ccache.table[chi] = 0;
1017     while ((cc = dir->ccache.table[from]) != 0) {	/* Loop invariants: chars[chi] == 0; */
1018         /* chars[chi+1..from] != 0. */
1019         uint fchi = chars_head_index(cc->code, cc_pair(cc));
1020 
1021         /* If chi <= fchi < from, we relocate the character. */
1022         /* Note that '<=' must take wraparound into account. */
1023         if ((chi < from ? chi <= fchi && fchi < from :
1024              chi <= fchi || fchi < from)
1025             ) {
1026             dir->ccache.table[chi] = cc;
1027             dir->ccache.table[from] = 0;
1028             chi = from;
1029         }
1030         from = (from + 1) & mask;
1031     }
1032 }
1033 
1034 /* Shorten a cached character. */
1035 /* diff >= sizeof(cached_char_head). */
1036 static void
shorten_cached_char(gs_font_dir * dir,cached_char * cc,uint diff)1037 shorten_cached_char(gs_font_dir * dir, cached_char * cc, uint diff)
1038 {
1039     gx_bits_cache_shorten((gx_bits_cache *) & dir->ccache, &cc->head,
1040                           diff, cc->chunk);
1041     if_debug2('K', "[K]shortening creates free block 0x%lx(%u)\n",
1042               (ulong) ((byte *) cc + cc->head.size), diff);
1043 }
1044 
1045 #ifdef GSLITE
1046 
gx_retain_cached_char(cached_char * cc)1047 void gx_retain_cached_char(cached_char *cc)
1048 {
1049     cc->dont_evict ++;
1050 }
1051 
gx_release_cached_char(cached_char * cc)1052 void gx_release_cached_char(cached_char *cc)
1053 {
1054     cc->dont_evict --;
1055 }
1056 
1057 #endif
1058