xref: /plan9/sys/src/cmd/gs/src/gsgcache.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1996, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gsgcache.c,v 1.4 2005/06/21 16:25:50 igor Exp $ */
18 /* Glyph data cache methods. */
19 
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "memory_.h"
23 #include "gsstruct.h"
24 #include "gsgdata.h"
25 #include "gsgcache.h"
26 #include "gxfont.h"
27 #include "gxfont42.h"
28 
29 /*
30  * This implementation hardcodes the type 42 font type.
31  * We could generalize it, but since CIDFontType 0 uses
32  * a PS procedure for reading glyphs, it is hardly applicable.
33  *
34  * The caching is mostly useful for glyphs with multiple components,
35  * but CIDFontType 0 has 2 components max, which are relatively seldom.
36  * Also it is low useful for fonts, which fully loaded into RAM.
37  * FAPI does not need a caching, because renderer pludins access
38  * font data through a file handle by own means.
39  *
40  * Due to all above, currently the caching is applied
41  * only while emulating CIDFontType 2 with a True Type file.
42  */
43 
44 typedef struct gs_glyph_cache_elem_s gs_glyph_cache_elem;
45 struct gs_glyph_cache_elem_s {
46     gs_glyph_data_t gd;
47     uint glyph_index;
48     uint lock_count;
49     gs_glyph_cache_elem *next;
50 };
51 gs_public_st_composite(st_glyph_cache_elem, gs_glyph_cache_elem, "gs_glyph_cache_elem",
52     gs_glyph_cache_elem_enum_ptrs, gs_glyph_cache_elem_reloc_ptrs);
53 
54 private
ENUM_PTRS_WITH(gs_glyph_cache_elem_enum_ptrs,gs_glyph_cache_elem * e)55 ENUM_PTRS_WITH(gs_glyph_cache_elem_enum_ptrs, gs_glyph_cache_elem *e)
56 {
57     index --;
58     if (index < ST_GLYPH_DATA_NUM_PTRS)
59 	return ENUM_USING(st_glyph_data, &e->gd, sizeof(e->gd), index);
60     return 0;
61 }
62 ENUM_PTR(0, gs_glyph_cache_elem, next);
63 ENUM_PTRS_END
RELOC_PTRS_WITH(gs_glyph_cache_elem_reloc_ptrs,gs_glyph_cache_elem * e)64 private RELOC_PTRS_WITH(gs_glyph_cache_elem_reloc_ptrs, gs_glyph_cache_elem *e)
65 {
66     RELOC_PTR(gs_glyph_cache_elem, next);
67     RELOC_USING(st_glyph_data, &e->gd, sizeof(e->gd));
68 } RELOC_PTRS_END
69 
70 struct gs_glyph_cache_s {
71     int total_size;
72     gs_glyph_cache_elem *list;
73     gs_memory_t *memory;
74     gs_font_type42 *pfont;
75     stream *s;
76     get_glyph_data_from_file read_data;
77 };
78 gs_private_st_ptrs4(st_glyph_cache, gs_glyph_cache, "gs_glyph_cache",
79     gs_glyph_cache_enum_ptrs, gs_glyph_cache_reloc_ptrs, list, memory, pfont, s);
80 
81 GS_NOTIFY_PROC(gs_glpyh_cache__release);
82 
83 gs_glyph_cache *
gs_glyph_cache__alloc(gs_font_type42 * pfont,stream * s,get_glyph_data_from_file read_data)84 gs_glyph_cache__alloc(gs_font_type42 *pfont, stream *s,
85 			get_glyph_data_from_file read_data)
86 {
87     gs_memory_t *mem = pfont->memory->stable_memory;
88     gs_glyph_cache *gdcache = (gs_glyph_cache *)gs_alloc_struct(mem,
89 	    gs_glyph_cache, &st_glyph_cache, "gs_glyph_cache");
90     if (gdcache == 0)
91 	return 0;
92     gdcache->total_size = 0;
93     gdcache->list = NULL;
94     gdcache->pfont = pfont;
95     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     gdcache->memory = mem;
102     gdcache->read_data = read_data;
103     gs_font_notify_register((gs_font *)pfont, gs_glyph_cache__release, (void *)gdcache);
104     return gdcache;
105 }
106 
107 int
gs_glyph_cache__release(void * data,void * event)108 gs_glyph_cache__release(void *data, void *event)
109 {
110     gs_glyph_cache *this = (gs_glyph_cache *)data;
111     gs_glyph_cache_elem *e = this->list;
112     gs_font_type42 *pfont = this->pfont;
113 
114     while (e != NULL) {
115 	gs_glyph_cache_elem *next_e;
116 
117 	next_e = e->next;
118 	e->gd.procs->free(&e->gd, "gs_glyph_cache__release");
119 	gs_free_object(this->memory, e, "gs_glyph_cache_elem__release");
120 	e = next_e;
121     }
122     this->list = NULL;
123     gs_font_notify_unregister((gs_font *)pfont, gs_glyph_cache__release, (void *)this);
124     gs_free_object(this->memory, this, "gs_glyph_cache__release");
125     return 0;
126 }
127 
128 private gs_glyph_cache_elem **
gs_glyph_cache_elem__locate(gs_glyph_cache * this,uint glyph_index)129 gs_glyph_cache_elem__locate(gs_glyph_cache *this, uint glyph_index)
130 {   /* If not fond, returns an unlocked element. */
131     gs_glyph_cache_elem **e = &this->list, **p_unlocked = NULL;
132     int count = 0; /* debug purpose only */
133 
134     for (; *e != 0; e = &(*e)->next, count++) {
135 	if ((*e)->glyph_index == glyph_index) {
136 	    return e;
137 	}
138 	if ((*e)->lock_count == 0)
139 	    p_unlocked = e;
140     }
141     return p_unlocked;
142 }
143 
144 private inline void
gs_glyph_cache_elem__move_to_head(gs_glyph_cache * this,gs_glyph_cache_elem ** pe)145 gs_glyph_cache_elem__move_to_head(gs_glyph_cache *this, gs_glyph_cache_elem **pe)
146 {   gs_glyph_cache_elem *e = *pe;
147 
148     *pe = e->next;
149     e->next = this->list;
150     this->list = e;
151 }
152 
153 /* Manage the glyph data using the font's allocator. */
154 private void
gs_glyph_cache_elem__free_data(gs_glyph_data_t * pgd,client_name_t cname)155 gs_glyph_cache_elem__free_data(gs_glyph_data_t *pgd, client_name_t cname)
156 {   gs_glyph_cache_elem *e = (gs_glyph_cache_elem *)pgd->proc_data;
157 
158     e->lock_count--;
159 }
160 private int
gs_glyph_cache_elem__substring(gs_glyph_data_t * pgd,uint offset,uint size)161 gs_glyph_cache_elem__substring(gs_glyph_data_t *pgd, uint offset, uint size)
162 {   gs_glyph_cache_elem *e = (gs_glyph_cache_elem *)pgd->proc_data;
163 
164     e->lock_count++;
165     return_error(gs_error_unregistered); /* Unsupported; should not happen. */
166 }
167 
168 private const gs_glyph_data_procs_t gs_glyph_cache_elem_procs = {
169     gs_glyph_cache_elem__free_data, gs_glyph_cache_elem__substring
170 };
171 
172 int
gs_get_glyph_data_cached(gs_font_type42 * pfont,uint glyph_index,gs_glyph_data_t * pgd)173 gs_get_glyph_data_cached(gs_font_type42 *pfont, uint glyph_index, gs_glyph_data_t *pgd)
174 {   gs_glyph_cache *gdcache = pfont->data.gdcache;
175     gs_glyph_cache_elem **pe = gs_glyph_cache_elem__locate(gdcache, glyph_index);
176     gs_glyph_cache_elem *e = NULL;
177 
178     if (pe == NULL || (*pe)->glyph_index != glyph_index) {
179 	int code;
180 
181 	if (pe != NULL && gdcache->total_size > 32767 /* arbitrary */ &&
182 			  (*pe)->lock_count <= 0) {
183 	    /* Release the element's data, and move it : */
184 	    e = *pe;
185 	    gdcache->total_size -= e->gd.bits.size + sizeof(*e);
186 	    e->gd.procs->free(&e->gd, "gs_get_glyph_data_cached");
187 	    gs_glyph_cache_elem__move_to_head(gdcache, pe);
188 	} else {
189 	    /* Allocate new head element. */
190 	    e = (gs_glyph_cache_elem *)gs_alloc_struct(gdcache->memory,
191 		gs_glyph_cache_elem, &st_glyph_cache_elem, "gs_glyph_cache_elem");
192 	    if (e == NULL)
193 		return_error(gs_error_VMerror);
194 	    memset(e, 0, sizeof(*e));
195 	    e->next = gdcache->list;
196 	    gdcache->list = e;
197 	    e->gd.memory = gdcache->memory;
198 	}
199         /* Load the element's data : */
200 	code = (*gdcache->read_data)(pfont, gdcache->s, glyph_index, &e->gd);
201 	if (code < 0)
202 	    return code;
203         gdcache->total_size += e->gd.bits.size + sizeof(*e);
204 	e->glyph_index = glyph_index;
205     } else {
206         /* Move the element : */
207 	e = *pe;
208 	gs_glyph_cache_elem__move_to_head(gdcache, pe);
209     }
210     /* Copy data and set procs : */
211     pgd->bits = e->gd.bits;
212     pgd->proc_data = e;
213     pgd->procs = &gs_glyph_cache_elem_procs;
214     e->lock_count++;
215     return 0;
216 }
217 
218 
219 
220 
221