Coverage Report

Created: 2025-06-24 07:01

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