Coverage Report

Created: 2025-06-10 06:49

/src/ghostpdl/base/gsgcache.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
/* Glyph data cache methods. */
18
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "memory_.h"
22
#include "gsstruct.h"
23
#include "gsgdata.h"
24
#include "gsgcache.h"
25
#include "gxfont.h"
26
#include "gxfont42.h"
27
28
/*
29
 * This implementation hardcodes the type 42 font type.
30
 * We could generalize it, but since CIDFontType 0 uses
31
 * a PS procedure for reading glyphs, it is hardly applicable.
32
 *
33
 * The caching is mostly useful for glyphs with multiple components,
34
 * but CIDFontType 0 has 2 components max, which are relatively seldom.
35
 * Also it is low useful for fonts, which fully loaded into RAM.
36
 * FAPI does not need a caching, because renderer pludins access
37
 * font data through a file handle by own means.
38
 *
39
 * Due to all above, currently the caching is applied
40
 * only while emulating CIDFontType 2 with a True Type file.
41
 */
42
43
typedef struct gs_glyph_cache_elem_s gs_glyph_cache_elem;
44
struct gs_glyph_cache_elem_s {
45
    gs_glyph_data_t gd;
46
    uint glyph_index;
47
    uint lock_count;
48
    gs_glyph_cache_elem *next;
49
};
50
gs_private_st_composite(st_glyph_cache_elem, gs_glyph_cache_elem, "gs_glyph_cache_elem",
51
    gs_glyph_cache_elem_enum_ptrs, gs_glyph_cache_elem_reloc_ptrs);
52
53
static
54
0
ENUM_PTRS_WITH(gs_glyph_cache_elem_enum_ptrs, gs_glyph_cache_elem *e)
55
0
{
56
0
    index --;
57
0
    if (index < ST_GLYPH_DATA_NUM_PTRS)
58
0
        return ENUM_USING(st_glyph_data, &e->gd, sizeof(e->gd), index);
59
0
    return 0;
60
0
}
61
0
ENUM_PTR(0, gs_glyph_cache_elem, next);
62
0
ENUM_PTRS_END
63
0
static RELOC_PTRS_WITH(gs_glyph_cache_elem_reloc_ptrs, gs_glyph_cache_elem *e)
64
0
{
65
0
    RELOC_PTR(gs_glyph_cache_elem, next);
66
0
    RELOC_USING(st_glyph_data, &e->gd, sizeof(e->gd));
67
0
} RELOC_PTRS_END
68
69
struct gs_glyph_cache_s {
70
    int total_size;
71
    gs_glyph_cache_elem *list;
72
    gs_memory_t *memory;
73
    gs_font_type42 *pfont;
74
    stream *s;
75
    get_glyph_data_from_file read_data;
76
};
77
gs_private_st_ptrs4(st_glyph_cache, gs_glyph_cache, "gs_glyph_cache",
78
    gs_glyph_cache_enum_ptrs, gs_glyph_cache_reloc_ptrs, list, memory, pfont, s);
79
80
GS_NOTIFY_PROC(gs_glpyh_cache__release);
81
82
gs_glyph_cache *
83
gs_glyph_cache__alloc(gs_font_type42 *pfont, stream *s,
84
                        get_glyph_data_from_file read_data)
85
0
{
86
0
    int code;
87
0
    gs_memory_t *mem = pfont->memory->stable_memory;
88
0
    gs_glyph_cache *gdcache = (gs_glyph_cache *)gs_alloc_struct(mem,
89
0
            gs_glyph_cache, &st_glyph_cache, "gs_glyph_cache");
90
0
    if (gdcache == 0)
91
0
        return 0;
92
0
    gdcache->total_size = 0;
93
0
    gdcache->list = NULL;
94
0
    gdcache->pfont = pfont;
95
0
    gdcache->s = s;
96
    /*
97
    * The cache elements need to be in stable memory so they don't
98
    * get removed by 'restore' (elements can be created at a different
99
    * save level than the current level)
100
    */
101
0
    gdcache->memory = mem;
102
0
    gdcache->read_data = read_data;
103
0
    code = gs_font_notify_register((gs_font *)pfont, gs_glyph_cache__release, (void *)gdcache);
104
0
    if (code < 0) {
105
0
        gs_free_object(mem, gdcache, "gs_glyph_cache__alloc");
106
0
        gdcache = NULL;
107
0
    }
108
0
    return gdcache;
109
0
}
110
111
int
112
gs_glyph_cache__release(void *data, void *event)
113
0
{
114
0
    gs_glyph_cache *self = (gs_glyph_cache *)data;
115
0
    gs_glyph_cache_elem *e = self->list;
116
0
    gs_font_type42 *pfont = self->pfont;
117
118
0
    while (e != NULL) {
119
0
        gs_glyph_cache_elem *next_e;
120
121
0
        next_e = e->next;
122
0
        e->gd.procs->free(&e->gd, "gs_glyph_cache__release");
123
0
        gs_free_object(self->memory, e, "gs_glyph_cache_elem__release");
124
0
        e = next_e;
125
0
    }
126
0
    self->list = NULL;
127
0
    gs_font_notify_unregister((gs_font *)pfont, gs_glyph_cache__release, (void *)self);
128
0
    gs_free_object(self->memory, self, "gs_glyph_cache__release");
129
0
    return 0;
130
0
}
131
132
static gs_glyph_cache_elem **
133
gs_glyph_cache_elem__locate(gs_glyph_cache *self, uint glyph_index)
134
0
{   /* If not fond, returns an unlocked element. */
135
0
    gs_glyph_cache_elem **e = &self->list, **p_unlocked = NULL;
136
0
    int count = 0; /* debug purpose only */
137
138
0
    for (; *e != 0; e = &(*e)->next, count++) {
139
0
        if ((*e)->glyph_index == glyph_index) {
140
0
            return e;
141
0
        }
142
0
        if ((*e)->lock_count == 0)
143
0
            p_unlocked = e;
144
0
    }
145
0
    return p_unlocked;
146
0
}
147
148
static inline void
149
gs_glyph_cache_elem__move_to_head(gs_glyph_cache *self, gs_glyph_cache_elem **pe)
150
0
{   gs_glyph_cache_elem *e = *pe;
151
152
0
    *pe = e->next;
153
0
    e->next = self->list;
154
0
    self->list = e;
155
0
}
156
157
/* Manage the glyph data using the font's allocator. */
158
static void
159
gs_glyph_cache_elem__free_data(gs_glyph_data_t *pgd, client_name_t cname)
160
0
{   gs_glyph_cache_elem *e = (gs_glyph_cache_elem *)pgd->proc_data;
161
162
0
    e->lock_count--;
163
0
}
164
static int
165
gs_glyph_cache_elem__substring(gs_glyph_data_t *pgd, uint offset, uint size)
166
0
{   gs_glyph_cache_elem *e = (gs_glyph_cache_elem *)pgd->proc_data;
167
168
0
    e->lock_count++;
169
0
    return_error(gs_error_unregistered); /* Unsupported; should not happen. */
170
0
}
171
172
static const gs_glyph_data_procs_t gs_glyph_cache_elem_procs = {
173
    gs_glyph_cache_elem__free_data, gs_glyph_cache_elem__substring
174
};
175
176
int
177
gs_get_glyph_data_cached(gs_font_type42 *pfont, uint glyph_index, gs_glyph_data_t *pgd)
178
0
{   gs_glyph_cache *gdcache = pfont->data.gdcache;
179
0
    gs_glyph_cache_elem **pe = gs_glyph_cache_elem__locate(gdcache, glyph_index);
180
0
    gs_glyph_cache_elem *e = NULL;
181
182
0
    if (pe == NULL || (*pe)->glyph_index != glyph_index) {
183
0
        int code;
184
185
0
        if (pe != NULL && gdcache->total_size > 32767 /* arbitrary */ &&
186
0
                          (*pe)->lock_count <= 0) {
187
            /* Release the element's data, and move it : */
188
0
            e = *pe;
189
0
            gdcache->total_size -= e->gd.bits.size + sizeof(*e);
190
0
            e->gd.procs->free(&e->gd, "gs_get_glyph_data_cached");
191
0
            gs_glyph_cache_elem__move_to_head(gdcache, pe);
192
0
        } else {
193
            /* Allocate new head element. */
194
0
            e = (gs_glyph_cache_elem *)gs_alloc_struct(gdcache->memory,
195
0
                gs_glyph_cache_elem, &st_glyph_cache_elem, "gs_glyph_cache_elem");
196
0
            if (e == NULL)
197
0
                return_error(gs_error_VMerror);
198
0
            memset(e, 0, sizeof(*e));
199
0
            e->next = gdcache->list;
200
0
            gdcache->list = e;
201
0
            e->gd.memory = gdcache->memory;
202
0
        }
203
        /* Load the element's data : */
204
0
        code = (*gdcache->read_data)(pfont, gdcache->s, glyph_index, &e->gd);
205
0
        if (code < 0)
206
0
            return code;
207
0
        gdcache->total_size += e->gd.bits.size + sizeof(*e);
208
0
        e->glyph_index = glyph_index;
209
0
    } else {
210
        /* Move the element : */
211
0
        e = *pe;
212
0
        gs_glyph_cache_elem__move_to_head(gdcache, pe);
213
0
    }
214
    /* Copy data and set procs : */
215
0
    pgd->bits = e->gd.bits;
216
0
    pgd->proc_data = e;
217
0
    pgd->procs = &gs_glyph_cache_elem_procs;
218
0
    e->lock_count++;
219
0
    return 0;
220
0
}