/src/ghostpdl/base/gscicach.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 | | /* A color index cache. */ |
18 | | #include "gx.h" |
19 | | #include "gserrors.h" |
20 | | #include "gsccolor.h" |
21 | | #include "gxcspace.h" |
22 | | #include "gxdcolor.h" |
23 | | #include "gscicach.h" |
24 | | #include "memory_.h" |
25 | | |
26 | 189M | #define COLOR_INDEX_CACHE_SIZE 256 |
27 | 143M | #define COLOR_INDEX_CACHE_CHAINS (COLOR_INDEX_CACHE_SIZE / 16) |
28 | | |
29 | | typedef struct gs_color_index_cache_elem_s gs_color_index_cache_elem_t; |
30 | | |
31 | | struct gs_color_index_cache_elem_s { |
32 | | union _color { |
33 | | gx_color_index cindex; |
34 | | ushort devn[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
35 | | } color; |
36 | | gx_device_color_type color_type; |
37 | | uint chain; |
38 | | uint prev, next; /* NULL for unused. */ |
39 | | uint touch_prev, touch_next; |
40 | | bool frac_values_done; |
41 | | }; |
42 | | |
43 | | struct gs_color_index_cache_s { |
44 | | const gs_color_space *direct_space; |
45 | | gs_gstate *pgs; |
46 | | gx_device *dev; |
47 | | gx_device *trans_dev; |
48 | | int client_num_components; |
49 | | int device_num_components; |
50 | | gs_memory_t *memory; |
51 | | int used; |
52 | | gs_color_index_cache_elem_t *buf; |
53 | | uint recent_touch; |
54 | | float *paint_values; |
55 | | frac31 *frac_values; |
56 | | int chains[COLOR_INDEX_CACHE_CHAINS]; |
57 | | /* Note : the 0th element of buf, paint_values, frac_values is never used, |
58 | | because we consider the index 0 as NULL |
59 | | just for a faster initialization. */ |
60 | 294M | # define MYNULL 0 |
61 | | }; |
62 | | |
63 | | gs_private_st_ptrs6(st_color_index_cache, gs_color_index_cache_t, "gs_color_index_cache_t", |
64 | | gs_color_index_cache_elem_ptrs, gs_color_index_cache_reloc_ptrs, |
65 | | direct_space, memory, buf, paint_values, frac_values, trans_dev); |
66 | | |
67 | | gs_color_index_cache_t * |
68 | | gs_color_index_cache_create(gs_memory_t *memory, const gs_color_space *direct_space, gx_device *dev, |
69 | | gs_gstate *pgs, bool need_frac, gx_device *trans_dev) |
70 | 252k | { |
71 | 252k | int client_num_components = cs_num_components(direct_space); |
72 | 252k | int device_num_components = trans_dev->color_info.num_components; |
73 | 252k | gs_color_index_cache_elem_t *buf = ( gs_color_index_cache_elem_t *)gs_alloc_byte_array(memory, COLOR_INDEX_CACHE_SIZE, |
74 | 252k | sizeof(gs_color_index_cache_elem_t), "gs_color_index_cache_create"); |
75 | 252k | float *paint_values = (float *)gs_alloc_byte_array(memory, COLOR_INDEX_CACHE_SIZE * client_num_components, |
76 | 252k | sizeof(float), "gs_color_index_cache_create"); |
77 | 252k | frac31 *frac_values = (need_frac ? (frac31 *)gs_alloc_byte_array(memory, COLOR_INDEX_CACHE_SIZE * device_num_components, |
78 | 252k | sizeof(frac31), "gs_color_index_cache_create") : NULL); |
79 | 252k | gs_color_index_cache_t *pcic = gs_alloc_struct(memory, gs_color_index_cache_t, &st_color_index_cache, "gs_color_index_cache_create"); |
80 | | |
81 | 252k | if (buf == NULL || paint_values == NULL || (need_frac && frac_values == NULL) || pcic == NULL) { |
82 | 0 | gs_free_object(memory, buf, "gs_color_index_cache_create"); |
83 | 0 | gs_free_object(memory, paint_values, "gs_color_index_cache_create"); |
84 | 0 | gs_free_object(memory, frac_values, "gs_color_index_cache_create"); |
85 | 0 | gs_free_object(memory, pcic, "gs_color_index_cache_create"); |
86 | 0 | return NULL; |
87 | 0 | } |
88 | 252k | memset(pcic, 0, sizeof(*pcic)); |
89 | 252k | memset(buf, 0, COLOR_INDEX_CACHE_SIZE * sizeof(gs_color_index_cache_elem_t)); |
90 | 252k | pcic->direct_space = direct_space; |
91 | 252k | pcic->pgs = pgs; |
92 | 252k | pcic->dev = dev; |
93 | 252k | pcic->trans_dev = trans_dev; |
94 | 252k | pcic->device_num_components = device_num_components; |
95 | 252k | pcic->client_num_components = client_num_components; |
96 | 252k | pcic->memory = memory; |
97 | 252k | pcic->used = 1; /* Never use the 0th element. */ |
98 | 252k | pcic->buf = buf; |
99 | 252k | pcic->recent_touch = MYNULL; |
100 | 252k | pcic->paint_values = paint_values; |
101 | 252k | pcic->frac_values = frac_values; |
102 | 252k | return pcic; |
103 | 252k | } |
104 | | |
105 | | void |
106 | | gs_color_index_cache_destroy(gs_color_index_cache_t *pcic) |
107 | 252k | { |
108 | 252k | gs_free_object(pcic->memory, pcic->buf, "gs_color_index_cache_create"); |
109 | 252k | gs_free_object(pcic->memory, pcic->paint_values, "gs_color_index_cache_create"); |
110 | 252k | gs_free_object(pcic->memory, pcic->frac_values, "gs_color_index_cache_create"); |
111 | 252k | pcic->buf = NULL; |
112 | 252k | pcic->paint_values = NULL; |
113 | 252k | pcic->frac_values = NULL; |
114 | 252k | gs_free_object(pcic->memory, pcic, "gs_color_index_cache_create"); |
115 | 252k | } |
116 | | |
117 | | static inline int |
118 | | hash_paint_values(const gs_color_index_cache_t *self, const float *paint_values) |
119 | 143M | { |
120 | 143M | int i; |
121 | 143M | float v = 0; |
122 | 143M | uint k = 0; |
123 | 143M | const uint a_prime = 79; |
124 | | |
125 | 668M | for (i = 0; i < self->client_num_components; i++) |
126 | 525M | v = v * a_prime + paint_values[i]; |
127 | | /* Don't know the range of v, so hash its bytes : */ |
128 | 715M | for(i = 0; i < sizeof(v); i++) |
129 | 572M | k = k * a_prime + ((byte *)&v)[i]; |
130 | 143M | return k % COLOR_INDEX_CACHE_CHAINS; |
131 | 143M | } |
132 | | |
133 | | static inline void |
134 | | exclude_from_chain(gs_color_index_cache_t *self, uint i) |
135 | 64.4M | { |
136 | 64.4M | uint co = self->buf[i].chain; |
137 | 64.4M | uint ip = self->buf[i].prev, in = self->buf[i].next; |
138 | | |
139 | 64.4M | self->buf[ip].next = in; |
140 | 64.4M | self->buf[in].prev = ip; |
141 | 64.4M | if (self->chains[co] == i) |
142 | 36.2M | self->chains[co] = in; |
143 | 64.4M | } |
144 | | |
145 | | static inline void |
146 | | include_into_chain(gs_color_index_cache_t *self, uint i, uint c) |
147 | 65.6M | { |
148 | 65.6M | if (self->chains[c] != MYNULL) { |
149 | 64.9M | uint in = self->chains[c], ip = self->buf[in].prev; |
150 | | |
151 | 64.9M | self->buf[i].next = in; |
152 | 64.9M | self->buf[i].prev = ip; |
153 | 64.9M | self->buf[in].prev = i; |
154 | 64.9M | self->buf[ip].next = i; |
155 | 64.9M | } else |
156 | 690k | self->buf[i].prev = self->buf[i].next = i; |
157 | 65.6M | self->chains[c] = i; |
158 | 65.6M | self->buf[i].chain = c; |
159 | 65.6M | } |
160 | | |
161 | | static inline void |
162 | | exclude_from_touch_list(gs_color_index_cache_t *self, uint i) |
163 | 84.4M | { |
164 | 84.4M | uint ip = self->buf[i].touch_prev, in = self->buf[i].touch_next; |
165 | | |
166 | 84.4M | self->buf[ip].touch_next = in; |
167 | 84.4M | self->buf[in].touch_prev = ip; |
168 | 84.4M | if (self->recent_touch == i) { |
169 | 0 | if (i == in) |
170 | 0 | self->recent_touch = MYNULL; |
171 | 0 | else |
172 | 0 | self->recent_touch = in; |
173 | 0 | } |
174 | 84.4M | } |
175 | | |
176 | | static inline void |
177 | | include_into_touch_list(gs_color_index_cache_t *self, uint i) |
178 | 85.6M | { |
179 | 85.6M | if (self->recent_touch != MYNULL) { |
180 | 85.3M | uint in = self->recent_touch, ip = self->buf[in].touch_prev; |
181 | | |
182 | 85.3M | self->buf[i].touch_next = in; |
183 | 85.3M | self->buf[i].touch_prev = ip; |
184 | 85.3M | self->buf[in].touch_prev = i; |
185 | 85.3M | self->buf[ip].touch_next = i; |
186 | 85.3M | } else |
187 | 250k | self->buf[i].touch_prev = self->buf[i].touch_next = i; |
188 | 85.6M | self->recent_touch = i; |
189 | 85.6M | } |
190 | | |
191 | | static int |
192 | | get_color_index_cache_elem(gs_color_index_cache_t *self, |
193 | | const float *paint_values, uint *pi) |
194 | 143M | { |
195 | 143M | int client_num_components = self->client_num_components; |
196 | 143M | uint c = hash_paint_values(self, paint_values); |
197 | 143M | uint i = self->chains[c], j; |
198 | | |
199 | 143M | if (i != MYNULL) { |
200 | 142M | uint tries = 16; /* Arbitrary. */ |
201 | | |
202 | 142M | if (!memcmp(paint_values, self->paint_values + i * client_num_components, |
203 | 142M | sizeof(*paint_values) * client_num_components)) { |
204 | 77.5M | if (self->recent_touch != i) { |
205 | 64.6M | exclude_from_touch_list(self, i); |
206 | 64.6M | include_into_touch_list(self, i); |
207 | 64.6M | } |
208 | 77.5M | *pi = i; |
209 | 77.5M | return 1; |
210 | 77.5M | } |
211 | 709M | for (j = self->buf[i].next; tries -- && j != i; j = self->buf[j].next) { |
212 | 664M | if (!memcmp(paint_values, self->paint_values + j * client_num_components, |
213 | 664M | sizeof(*paint_values) * client_num_components)) { |
214 | 19.8M | exclude_from_chain(self, j); |
215 | 19.8M | include_into_chain(self, j, c); |
216 | 19.8M | if (self->recent_touch != j) { |
217 | 19.8M | exclude_from_touch_list(self, j); |
218 | 19.8M | include_into_touch_list(self, j); |
219 | 19.8M | } |
220 | 19.8M | *pi = j; |
221 | 19.8M | return 1; |
222 | 19.8M | } |
223 | 664M | } |
224 | 64.9M | } |
225 | 45.8M | if (self->used < COLOR_INDEX_CACHE_SIZE) { |
226 | | /* Use a new one */ |
227 | 1.21M | i = self->used++; |
228 | 1.21M | include_into_touch_list(self, i); |
229 | 44.6M | } else { |
230 | 44.6M | i = self->recent_touch; |
231 | 44.6M | self->recent_touch = self->buf[i].touch_prev; /* Assuming the cyclic list, |
232 | | just move the head pointer to the last element. */ |
233 | 44.6M | exclude_from_chain(self, i); |
234 | 44.6M | } |
235 | 45.8M | include_into_chain(self, i, c); |
236 | 45.8M | *pi = i; |
237 | 45.8M | return 0; |
238 | 143M | } |
239 | | |
240 | | static inline void |
241 | | compute_frac_values(gs_color_index_cache_t *self, uint i) |
242 | 45.2M | { |
243 | | |
244 | 45.2M | const gx_device_color_info *cinfo = &self->trans_dev->color_info; |
245 | 45.2M | int device_num_components = self->device_num_components; |
246 | 45.2M | int j; |
247 | 45.2M | gx_color_index c; |
248 | | |
249 | 45.2M | if (self->buf[i].color_type == &gx_dc_type_data_pure) { |
250 | 38.0M | c = self->buf[i].color.cindex; |
251 | 142M | for (j = 0; j < device_num_components; j++) { |
252 | 104M | int shift = cinfo->comp_shift[j]; |
253 | 104M | int bits = cinfo->comp_bits[j]; |
254 | 104M | self->frac_values[i * device_num_components + j] = |
255 | 104M | ((c >> shift) & ((1 << bits) - 1)) << |
256 | 104M | (sizeof(frac31) * 8 - 1 - bits); |
257 | 104M | } |
258 | 38.0M | self->buf[i].frac_values_done = true; |
259 | 38.0M | } else { |
260 | | /* Must be devn */ |
261 | 35.7M | for (j = 0; j < device_num_components; j++) { |
262 | 28.6M | self->frac_values[i * device_num_components + j] = |
263 | 28.6M | cv2frac31(self->buf[i].color.devn[j]); |
264 | 28.6M | } |
265 | 7.15M | self->buf[i].frac_values_done = true; |
266 | 7.15M | } |
267 | 45.2M | } |
268 | | |
269 | | int |
270 | | gs_cached_color_index(gs_color_index_cache_t *self, const float *paint_values, |
271 | | gx_device_color *pdevc, frac31 *frac_values) |
272 | 143M | { |
273 | | /* Must return 2 if the color is not pure. |
274 | | See patch_color_to_device_color. */ |
275 | 143M | const gs_color_space *pcs = self->direct_space; |
276 | 143M | int client_num_components = self->client_num_components; |
277 | 143M | int device_num_components = self->device_num_components; |
278 | 143M | uint i, j; |
279 | 143M | int code; |
280 | | |
281 | 143M | if (get_color_index_cache_elem(self, paint_values, &i)) { |
282 | 97.3M | if (pdevc != NULL) { |
283 | 83.5M | if (self->buf[i].color_type == &gx_dc_type_data_pure) { |
284 | 67.5M | pdevc->colors.pure = self->buf[i].color.cindex; |
285 | 67.5M | pdevc->type = &gx_dc_type_data_pure; |
286 | 67.5M | memcpy(pdevc->ccolor.paint.values, paint_values, |
287 | 67.5M | sizeof(*paint_values) * client_num_components); |
288 | 67.5M | } else { |
289 | | /* devn case */ |
290 | 79.7M | for (j = 0; j < device_num_components; j++) { |
291 | 63.7M | pdevc->colors.devn.values[j] = self->buf[i].color.devn[j]; |
292 | 63.7M | } |
293 | 15.9M | pdevc->type = &gx_dc_type_data_devn; |
294 | 15.9M | memcpy(pdevc->ccolor.paint.values, paint_values, |
295 | 15.9M | sizeof(*paint_values) * client_num_components); |
296 | 15.9M | } |
297 | 83.5M | pdevc->ccolor_valid = true; |
298 | 83.5M | } |
299 | 97.3M | if (frac_values != NULL && !self->buf[i].frac_values_done) |
300 | 232k | compute_frac_values(self, i); |
301 | 97.3M | } else { |
302 | 45.8M | gx_device_color devc_local; |
303 | 45.8M | gs_client_color fcc; |
304 | | |
305 | 45.8M | if (pdevc == NULL) |
306 | 5.32M | pdevc = &devc_local; |
307 | 45.8M | memcpy(self->paint_values + i * client_num_components, paint_values, |
308 | 45.8M | sizeof(*paint_values) * client_num_components); |
309 | 45.8M | memcpy(fcc.paint.values, paint_values, |
310 | 45.8M | sizeof(*paint_values) * client_num_components); |
311 | 45.8M | code = pcs->type->remap_color(&fcc, pcs, pdevc, self->pgs, |
312 | 45.8M | self->trans_dev, gs_color_select_texture); |
313 | 45.8M | if (code < 0) |
314 | 0 | return code; |
315 | 45.8M | if (pdevc->type == &gx_dc_type_data_pure) { |
316 | 38.6M | self->buf[i].color.cindex = pdevc->colors.pure; |
317 | 38.6M | } else if (pdevc->type == &gx_dc_type_data_devn) { |
318 | 36.0M | for (j = 0; j < device_num_components; j++) { |
319 | 28.8M | self->buf[i].color.devn[j] = pdevc->colors.devn.values[j]; |
320 | 28.8M | } |
321 | 7.20M | } else { |
322 | 0 | return 2; |
323 | 0 | } |
324 | 45.8M | self->buf[i].color_type = pdevc->type; |
325 | 45.8M | if (frac_values != NULL) |
326 | 45.0M | compute_frac_values(self, i); |
327 | 820k | else |
328 | 820k | self->buf[i].frac_values_done = false; |
329 | 45.8M | } |
330 | 143M | if (frac_values != NULL) |
331 | 141M | memcpy(frac_values, self->frac_values + i * device_num_components, |
332 | 141M | sizeof(*frac_values) * device_num_components); |
333 | 143M | return 0; |
334 | 143M | } |