1 /* Copyright (C) 1992, 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: zcie.c,v 1.13 2005/07/28 15:24:29 alexcher Exp $ */
18 /* CIE color operators */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "ghost.h"
22 #include "oper.h"
23 #include "gsstruct.h"
24 #include "gxcspace.h" /* gscolor2.h requires gscspace.h */
25 #include "gscolor2.h"
26 #include "gscie.h"
27 #include "estack.h"
28 #include "ialloc.h"
29 #include "idict.h"
30 #include "idparam.h"
31 #include "igstate.h"
32 #include "icie.h"
33 #include "isave.h"
34 #include "ivmspace.h"
35 #include "store.h" /* for make_null */
36
37 /* Empty procedures */
38 static const ref empty_procs[4] =
39 {
40 empty_ref_data(t_array, a_readonly | a_executable),
41 empty_ref_data(t_array, a_readonly | a_executable),
42 empty_ref_data(t_array, a_readonly | a_executable),
43 empty_ref_data(t_array, a_readonly | a_executable)
44 };
45
46 /* ------ Parameter extraction utilities ------ */
47
48 /* Get a range array parameter from a dictionary. */
49 /* We know that count <= 4. */
50 int
dict_ranges_param(const gs_memory_t * mem,const ref * pdref,const char * kstr,int count,gs_range * prange)51 dict_ranges_param(const gs_memory_t *mem,
52 const ref * pdref, const char *kstr, int count,
53 gs_range * prange)
54 {
55 int code = dict_floats_param(mem, pdref, kstr, count * 2,
56 (float *)prange, NULL);
57
58 if (code < 0)
59 return code;
60 else if (code == 0)
61 memcpy(prange, Range4_default.ranges, count * sizeof(gs_range));
62 return 0;
63 }
64
65 /* Get an array of procedures from a dictionary. */
66 /* We know count <= countof(empty_procs). */
67 int
dict_proc_array_param(const gs_memory_t * mem,const ref * pdict,const char * kstr,uint count,ref * pparray)68 dict_proc_array_param(const gs_memory_t *mem,
69 const ref *pdict, const char *kstr,
70 uint count, ref *pparray)
71 {
72 ref *pvalue;
73
74 if (dict_find_string(pdict, kstr, &pvalue) > 0) {
75 uint i;
76
77 check_array_only(*pvalue);
78 if (r_size(pvalue) != count)
79 return_error(e_rangecheck);
80 for (i = 0; i < count; i++) {
81 ref proc;
82
83 array_get(mem, pvalue, (long)i, &proc);
84 check_proc_only(proc);
85 }
86 *pparray = *pvalue;
87 } else
88 make_const_array(pparray, a_readonly | avm_foreign,
89 count, &empty_procs[0]);
90 return 0;
91 }
92
93 /* Get 3 ranges from a dictionary. */
94 int
dict_range3_param(const gs_memory_t * mem,const ref * pdref,const char * kstr,gs_range3 * prange3)95 dict_range3_param(const gs_memory_t *mem,
96 const ref *pdref, const char *kstr,
97 gs_range3 *prange3)
98 {
99 return dict_ranges_param(mem, pdref, kstr, 3, prange3->ranges);
100 }
101
102 /* Get a 3x3 matrix from a dictionary. */
103 int
dict_matrix3_param(const gs_memory_t * mem,const ref * pdref,const char * kstr,gs_matrix3 * pmat3)104 dict_matrix3_param(const gs_memory_t *mem,
105 const ref *pdref, const char *kstr, gs_matrix3 *pmat3)
106 {
107 /*
108 * We can't simply call dict_float_array_param with the matrix
109 * cast to a 9-element float array, because compilers may insert
110 * padding elements after each of the vectors. However, we can be
111 * confident that there is no padding within a single vector.
112 */
113 float values[9], defaults[9];
114 int code;
115
116 memcpy(&defaults[0], &Matrix3_default.cu, 3 * sizeof(float));
117 memcpy(&defaults[3], &Matrix3_default.cv, 3 * sizeof(float));
118 memcpy(&defaults[6], &Matrix3_default.cw, 3 * sizeof(float));
119 code = dict_floats_param(mem, pdref, kstr, 9, values, defaults);
120 if (code < 0)
121 return code;
122 memcpy(&pmat3->cu, &values[0], 3 * sizeof(float));
123 memcpy(&pmat3->cv, &values[3], 3 * sizeof(float));
124 memcpy(&pmat3->cw, &values[6], 3 * sizeof(float));
125 return 0;
126 }
127
128 /* Get 3 procedures from a dictionary. */
129 int
dict_proc3_param(const gs_memory_t * mem,const ref * pdref,const char * kstr,ref proc3[3])130 dict_proc3_param(const gs_memory_t *mem, const ref *pdref, const char *kstr, ref proc3[3])
131 {
132 return dict_proc_array_param(mem, pdref, kstr, 3, proc3);
133 }
134
135 /* Get WhitePoint and BlackPoint values. */
136 int
cie_points_param(const gs_memory_t * mem,const ref * pdref,gs_cie_wb * pwb)137 cie_points_param(const gs_memory_t *mem,
138 const ref * pdref, gs_cie_wb * pwb)
139 {
140 int code;
141
142 if ((code = dict_floats_param(mem, pdref, "WhitePoint", 3, (float *)&pwb->WhitePoint, NULL)) < 0 ||
143 (code = dict_floats_param(mem, pdref, "BlackPoint", 3, (float *)&pwb->BlackPoint, (const float *)&BlackPoint_default)) < 0
144 )
145 return code;
146 if (pwb->WhitePoint.u <= 0 ||
147 pwb->WhitePoint.v != 1 ||
148 pwb->WhitePoint.w <= 0 ||
149 pwb->BlackPoint.u < 0 ||
150 pwb->BlackPoint.v < 0 ||
151 pwb->BlackPoint.w < 0
152 )
153 return_error(e_rangecheck);
154 return 0;
155 }
156
157 /* Process a 3- or 4-dimensional lookup table from a dictionary. */
158 /* The caller has set pclt->n and pclt->m. */
159 /* ptref is known to be a readable array of size at least n+1. */
160 private int cie_3d_table_param(const ref * ptable, uint count, uint nbytes,
161 gs_const_string * strings);
162 int
cie_table_param(const ref * ptref,gx_color_lookup_table * pclt,gs_memory_t * mem)163 cie_table_param(const ref * ptref, gx_color_lookup_table * pclt,
164 gs_memory_t * mem)
165 {
166 int n = pclt->n, m = pclt->m;
167 const ref *pta = ptref->value.const_refs;
168 int i;
169 uint nbytes;
170 int code;
171 gs_const_string *table;
172
173 for (i = 0; i < n; ++i) {
174 check_type_only(pta[i], t_integer);
175 if (pta[i].value.intval <= 1 || pta[i].value.intval > max_ushort)
176 return_error(e_rangecheck);
177 pclt->dims[i] = (int)pta[i].value.intval;
178 }
179 nbytes = m * pclt->dims[n - 2] * pclt->dims[n - 1];
180 if (n == 3) {
181 table =
182 gs_alloc_struct_array(mem, pclt->dims[0], gs_const_string,
183 &st_const_string_element, "cie_table_param");
184 if (table == 0)
185 return_error(e_VMerror);
186 code = cie_3d_table_param(pta + 3, pclt->dims[0], nbytes, table);
187 } else { /* n == 4 */
188 int d0 = pclt->dims[0], d1 = pclt->dims[1];
189 uint ntables = d0 * d1;
190 const ref *psuba;
191
192 check_read_type(pta[4], t_array);
193 if (r_size(pta + 4) != d0)
194 return_error(e_rangecheck);
195 table =
196 gs_alloc_struct_array(mem, ntables, gs_const_string,
197 &st_const_string_element, "cie_table_param");
198 if (table == 0)
199 return_error(e_VMerror);
200 psuba = pta[4].value.const_refs;
201 /*
202 * We know that d0 > 0, so code will always be set in the loop:
203 * we initialize code to 0 here solely to pacify stupid compilers.
204 */
205 for (code = 0, i = 0; i < d0; ++i) {
206 code = cie_3d_table_param(psuba + i, d1, nbytes, table + d1 * i);
207 if (code < 0)
208 break;
209 }
210 }
211 if (code < 0) {
212 gs_free_object(mem, table, "cie_table_param");
213 return code;
214 }
215 pclt->table = table;
216 return 0;
217 }
218 private int
cie_3d_table_param(const ref * ptable,uint count,uint nbytes,gs_const_string * strings)219 cie_3d_table_param(const ref * ptable, uint count, uint nbytes,
220 gs_const_string * strings)
221 {
222 const ref *rstrings;
223 uint i;
224
225 check_read_type(*ptable, t_array);
226 if (r_size(ptable) != count)
227 return_error(e_rangecheck);
228 rstrings = ptable->value.const_refs;
229 for (i = 0; i < count; ++i) {
230 const ref *const prt2 = rstrings + i;
231
232 check_read_type(*prt2, t_string);
233 if (r_size(prt2) != nbytes)
234 return_error(e_rangecheck);
235 strings[i].data = prt2->value.const_bytes;
236 strings[i].size = nbytes;
237 }
238 return 0;
239 }
240
241 /* ------ CIE setcolorspace ------ */
242
243 /* Common code for the CIEBased* cases of setcolorspace. */
244 private int
cie_lmnp_param(const gs_memory_t * mem,const ref * pdref,gs_cie_common * pcie,ref_cie_procs * pcprocs)245 cie_lmnp_param(const gs_memory_t *mem, const ref * pdref, gs_cie_common * pcie, ref_cie_procs * pcprocs)
246 {
247 int code;
248
249 if ((code = dict_range3_param(mem, pdref, "RangeLMN", &pcie->RangeLMN)) < 0 ||
250 (code = dict_proc3_param(mem, pdref, "DecodeLMN", &pcprocs->DecodeLMN)) < 0 ||
251 (code = dict_matrix3_param(mem, pdref, "MatrixLMN", &pcie->MatrixLMN)) < 0 ||
252 (code = cie_points_param(mem, pdref, &pcie->points)) < 0
253 )
254 return code;
255 pcie->DecodeLMN = DecodeLMN_default;
256 return 0;
257 }
258
259 /* Common code for the CIEBasedABC/DEF[G] cases of setcolorspace. */
260 private int
cie_abc_param(const gs_memory_t * mem,const ref * pdref,gs_cie_abc * pcie,ref_cie_procs * pcprocs)261 cie_abc_param(const gs_memory_t *mem, const ref * pdref, gs_cie_abc * pcie, ref_cie_procs * pcprocs)
262 {
263 int code;
264
265 if ((code = dict_range3_param(mem, pdref, "RangeABC", &pcie->RangeABC)) < 0 ||
266 (code = dict_proc3_param(mem, pdref, "DecodeABC", &pcprocs->Decode.ABC)) < 0 ||
267 (code = dict_matrix3_param(mem, pdref, "MatrixABC", &pcie->MatrixABC)) < 0 ||
268 (code = cie_lmnp_param(mem, pdref, &pcie->common, pcprocs)) < 0
269 )
270 return code;
271 pcie->DecodeABC = DecodeABC_default;
272 return 0;
273 }
274
275 /* Finish setting a CIE space (successful or not). */
276 int
cie_set_finish(i_ctx_t * i_ctx_p,gs_color_space * pcs,const ref_cie_procs * pcprocs,int edepth,int code)277 cie_set_finish(i_ctx_t *i_ctx_p, gs_color_space * pcs,
278 const ref_cie_procs * pcprocs, int edepth, int code)
279 {
280 if (code >= 0)
281 code = gs_setcolorspace(igs, pcs);
282 /* Delete the extra reference to the parameter tables. */
283 gs_cspace_release(pcs);
284 /* Free the top-level object, which was copied by gs_setcolorspace. */
285 gs_free_object(gs_state_memory(igs), pcs, "cie_set_finish");
286 if (code < 0) {
287 ref_stack_pop_to(&e_stack, edepth);
288 return code;
289 }
290 istate->colorspace.procs.cie = *pcprocs;
291 pop(1);
292 return (ref_stack_count(&e_stack) == edepth ? 0 : o_push_estack);
293 }
294
295 /* Forward references */
296 private int cache_common(i_ctx_t *, gs_cie_common *, const ref_cie_procs *,
297 void *, gs_ref_memory_t *);
298 private int cache_abc_common(i_ctx_t *, gs_cie_abc *, const ref_cie_procs *,
299 void *, gs_ref_memory_t *);
300
301 /* <dict> .setciedefgspace - */
302 private int cie_defg_finish(i_ctx_t *);
303 private int
zsetciedefgspace(i_ctx_t * i_ctx_p)304 zsetciedefgspace(i_ctx_t *i_ctx_p)
305 {
306 os_ptr op = osp;
307 int edepth = ref_stack_count(&e_stack);
308 gs_memory_t *mem = gs_state_memory(igs);
309 gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
310 gs_color_space *pcs;
311 ref_cie_procs procs;
312 gs_cie_defg *pcie;
313 int code;
314 ref *ptref;
315
316 check_type(*op, t_dictionary);
317 check_dict_read(*op);
318 if ((code = dict_find_string(op, "Table", &ptref)) <= 0)
319 return (code < 0 ? code : gs_note_error(e_rangecheck));
320 check_read_type(*ptref, t_array);
321 if (r_size(ptref) != 5)
322 return_error(e_rangecheck);
323 procs = istate->colorspace.procs.cie;
324 code = gs_cspace_build_CIEDEFG(&pcs, NULL, mem);
325 if (code < 0)
326 return code;
327 pcie = pcs->params.defg;
328 pcie->Table.n = 4;
329 pcie->Table.m = 3;
330 if ((code = dict_ranges_param(mem, op, "RangeDEFG", 4, pcie->RangeDEFG.ranges)) < 0 ||
331 (code = dict_proc_array_param(mem, op, "DecodeDEFG", 4, &procs.PreDecode.DEFG)) < 0 ||
332 (code = dict_ranges_param(mem, op, "RangeHIJK", 4, pcie->RangeHIJK.ranges)) < 0 ||
333 (code = cie_table_param(ptref, &pcie->Table, mem)) < 0 ||
334 (code = cie_abc_param(imemory, op, (gs_cie_abc *) pcie, &procs)) < 0 ||
335 (code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs, (gs_cie_common *)pcie, igs)) < 0 || /* do this last */
336 (code = cie_cache_push_finish(i_ctx_p, cie_defg_finish, imem, pcie)) < 0 ||
337 (code = cie_prepare_cache4(i_ctx_p, &pcie->RangeDEFG,
338 procs.PreDecode.DEFG.value.const_refs,
339 &pcie->caches_defg.DecodeDEFG[0],
340 pcie, imem, "Decode.DEFG")) < 0 ||
341 (code = cache_abc_common(i_ctx_p, (gs_cie_abc *)pcie, &procs, pcie, imem)) < 0
342 )
343 DO_NOTHING;
344 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
345 }
346 private int
cie_defg_finish(i_ctx_t * i_ctx_p)347 cie_defg_finish(i_ctx_t *i_ctx_p)
348 {
349 os_ptr op = osp;
350 gs_cie_defg *pcie = r_ptr(op, gs_cie_defg);
351
352 pcie->DecodeDEFG = DecodeDEFG_from_cache;
353 pcie->DecodeABC = DecodeABC_from_cache;
354 pcie->common.DecodeLMN = DecodeLMN_from_cache;
355 gs_cie_defg_complete(pcie);
356 pop(1);
357 return 0;
358 }
359
360 /* <dict> .setciedefspace - */
361 private int cie_def_finish(i_ctx_t *);
362 private int
zsetciedefspace(i_ctx_t * i_ctx_p)363 zsetciedefspace(i_ctx_t *i_ctx_p)
364 {
365 os_ptr op = osp;
366 int edepth = ref_stack_count(&e_stack);
367 gs_memory_t *mem = gs_state_memory(igs);
368 gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
369 gs_color_space *pcs;
370 ref_cie_procs procs;
371 gs_cie_def *pcie;
372 int code;
373 ref *ptref;
374
375 check_type(*op, t_dictionary);
376 check_dict_read(*op);
377 if ((code = dict_find_string(op, "Table", &ptref)) <= 0)
378 return (code < 0 ? code : gs_note_error(e_rangecheck));
379 check_read_type(*ptref, t_array);
380 if (r_size(ptref) != 4)
381 return_error(e_rangecheck);
382 procs = istate->colorspace.procs.cie;
383 code = gs_cspace_build_CIEDEF(&pcs, NULL, mem);
384 if (code < 0)
385 return code;
386 pcie = pcs->params.def;
387 pcie->Table.n = 3;
388 pcie->Table.m = 3;
389 if ((code = dict_range3_param(mem, op, "RangeDEF", &pcie->RangeDEF)) < 0 ||
390 (code = dict_proc3_param(mem, op, "DecodeDEF", &procs.PreDecode.DEF)) < 0 ||
391 (code = dict_range3_param(mem, op, "RangeHIJ", &pcie->RangeHIJ)) < 0 ||
392 (code = cie_table_param(ptref, &pcie->Table, mem)) < 0 ||
393 (code = cie_abc_param(imemory, op, (gs_cie_abc *) pcie, &procs)) < 0 ||
394 (code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs, (gs_cie_common *)pcie, igs)) < 0 || /* do this last */
395 (code = cie_cache_push_finish(i_ctx_p, cie_def_finish, imem, pcie)) < 0 ||
396 (code = cie_prepare_cache3(i_ctx_p, &pcie->RangeDEF,
397 procs.PreDecode.DEF.value.const_refs,
398 &pcie->caches_def.DecodeDEF[0],
399 pcie, imem, "Decode.DEF")) < 0 ||
400 (code = cache_abc_common(i_ctx_p, (gs_cie_abc *)pcie, &procs, pcie, imem)) < 0
401 )
402 DO_NOTHING;
403 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
404 }
405 private int
cie_def_finish(i_ctx_t * i_ctx_p)406 cie_def_finish(i_ctx_t *i_ctx_p)
407 {
408 os_ptr op = osp;
409 gs_cie_def *pcie = r_ptr(op, gs_cie_def);
410
411 pcie->DecodeDEF = DecodeDEF_from_cache;
412 pcie->DecodeABC = DecodeABC_from_cache;
413 pcie->common.DecodeLMN = DecodeLMN_from_cache;
414 gs_cie_def_complete(pcie);
415 pop(1);
416 return 0;
417 }
418
419 /* <dict> .setcieabcspace - */
420 private int cie_abc_finish(i_ctx_t *);
421 private int
zsetcieabcspace(i_ctx_t * i_ctx_p)422 zsetcieabcspace(i_ctx_t *i_ctx_p)
423 {
424 os_ptr op = osp;
425 int edepth = ref_stack_count(&e_stack);
426 gs_memory_t *mem = gs_state_memory(igs);
427 gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
428 gs_color_space *pcs;
429 ref_cie_procs procs;
430 gs_cie_abc *pcie;
431 int code;
432
433 check_type(*op, t_dictionary);
434 check_dict_read(*op);
435 procs = istate->colorspace.procs.cie;
436 code = gs_cspace_build_CIEABC(&pcs, NULL, mem);
437 if (code < 0)
438 return code;
439 pcie = pcs->params.abc;
440 code = cie_abc_param(imemory, op, pcie, &procs);
441 if (code < 0 ||
442 (code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs, (gs_cie_common *)pcie, igs)) < 0 || /* do this last */
443 (code = cie_cache_push_finish(i_ctx_p, cie_abc_finish, imem, pcie)) < 0 ||
444 (code = cache_abc_common(i_ctx_p, pcie, &procs, pcie, imem)) < 0
445 )
446 DO_NOTHING;
447 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
448 }
449 private int
cie_abc_finish(i_ctx_t * i_ctx_p)450 cie_abc_finish(i_ctx_t *i_ctx_p)
451 {
452 os_ptr op = osp;
453 gs_cie_abc *pcie = r_ptr(op, gs_cie_abc);
454
455 pcie->DecodeABC = DecodeABC_from_cache;
456 pcie->common.DecodeLMN = DecodeLMN_from_cache;
457 gs_cie_abc_complete(pcie);
458 pop(1);
459 return 0;
460 }
461
462 /* <dict> .setcieaspace - */
463 private int cie_a_finish(i_ctx_t *);
464 private int
zsetcieaspace(i_ctx_t * i_ctx_p)465 zsetcieaspace(i_ctx_t *i_ctx_p)
466 {
467 os_ptr op = osp;
468 int edepth = ref_stack_count(&e_stack);
469 gs_memory_t *mem = gs_state_memory(igs);
470 gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
471 gs_color_space *pcs;
472 ref_cie_procs procs;
473 gs_cie_a *pcie;
474 int code;
475
476 check_type(*op, t_dictionary);
477 check_dict_read(*op);
478 procs = istate->colorspace.procs.cie;
479 if ((code = dict_proc_param(op, "DecodeA", &procs.Decode.A, true)) < 0)
480 return code;
481 code = gs_cspace_build_CIEA(&pcs, NULL, mem);
482 if (code < 0)
483 return code;
484 pcie = pcs->params.a;
485 if ((code = dict_floats_param(imemory, op, "RangeA", 2, (float *)&pcie->RangeA, (const float *)&RangeA_default)) < 0 ||
486 (code = dict_floats_param(imemory, op, "MatrixA", 3, (float *)&pcie->MatrixA, (const float *)&MatrixA_default)) < 0 ||
487 (code = cie_lmnp_param(imemory, op, &pcie->common, &procs)) < 0 ||
488 (code = cie_cache_joint(i_ctx_p, &istate->colorrendering.procs, (gs_cie_common *)pcie, igs)) < 0 || /* do this last */
489 (code = cie_cache_push_finish(i_ctx_p, cie_a_finish, imem, pcie)) < 0 ||
490 (code = cie_prepare_cache(i_ctx_p, &pcie->RangeA, &procs.Decode.A, &pcie->caches.DecodeA.floats, pcie, imem, "Decode.A")) < 0 ||
491 (code = cache_common(i_ctx_p, &pcie->common, &procs, pcie, imem)) < 0
492 )
493 DO_NOTHING;
494 pcie->DecodeA = DecodeA_default;
495 return cie_set_finish(i_ctx_p, pcs, &procs, edepth, code);
496 }
497 private int
cie_a_finish(i_ctx_t * i_ctx_p)498 cie_a_finish(i_ctx_t *i_ctx_p)
499 {
500 os_ptr op = osp;
501 gs_cie_a *pcie = r_ptr(op, gs_cie_a);
502
503 pcie->DecodeA = DecodeA_from_cache;
504 pcie->common.DecodeLMN = DecodeLMN_from_cache;
505 gs_cie_a_complete(pcie);
506 pop(1);
507 return 0;
508 }
509
510 /* Common cache code */
511
512 private int
cache_abc_common(i_ctx_t * i_ctx_p,gs_cie_abc * pcie,const ref_cie_procs * pcprocs,void * container,gs_ref_memory_t * imem)513 cache_abc_common(i_ctx_t *i_ctx_p, gs_cie_abc * pcie,
514 const ref_cie_procs * pcprocs,
515 void *container, gs_ref_memory_t * imem)
516 {
517 int code =
518 cie_prepare_cache3(i_ctx_p, &pcie->RangeABC,
519 pcprocs->Decode.ABC.value.const_refs,
520 pcie->caches.DecodeABC.caches, pcie, imem,
521 "Decode.ABC");
522
523 return (code < 0 ? code :
524 cache_common(i_ctx_p, &pcie->common, pcprocs, pcie, imem));
525 }
526
527 private int
cache_common(i_ctx_t * i_ctx_p,gs_cie_common * pcie,const ref_cie_procs * pcprocs,void * container,gs_ref_memory_t * imem)528 cache_common(i_ctx_t *i_ctx_p, gs_cie_common * pcie,
529 const ref_cie_procs * pcprocs,
530 void *container, gs_ref_memory_t * imem)
531 {
532 return cie_prepare_cache3(i_ctx_p, &pcie->RangeLMN,
533 pcprocs->DecodeLMN.value.const_refs,
534 &pcie->caches.DecodeLMN[0], container, imem,
535 "Decode.LMN");
536 }
537
538 /* ------ Internal routines ------ */
539
540 /* Prepare to cache the values for one or more procedures. */
541 private int cie_cache_finish1(i_ctx_t *);
542 private int cie_cache_finish(i_ctx_t *);
543 int
cie_prepare_cache(i_ctx_t * i_ctx_p,const gs_range * domain,const ref * proc,cie_cache_floats * pcache,void * container,gs_ref_memory_t * imem,client_name_t cname)544 cie_prepare_cache(i_ctx_t *i_ctx_p, const gs_range * domain, const ref * proc,
545 cie_cache_floats * pcache, void *container,
546 gs_ref_memory_t * imem, client_name_t cname)
547 {
548 int space = imemory_space(imem);
549 gs_sample_loop_params_t lp;
550 es_ptr ep;
551
552 gs_cie_cache_init(&pcache->params, &lp, domain, cname);
553 pcache->params.is_identity = r_size(proc) == 0;
554 check_estack(9);
555 ep = esp;
556 make_real(ep + 9, lp.A);
557 make_int(ep + 8, lp.N);
558 make_real(ep + 7, lp.B);
559 ep[6] = *proc;
560 r_clear_attrs(ep + 6, a_executable);
561 make_op_estack(ep + 5, zcvx);
562 make_op_estack(ep + 4, zfor_samples);
563 make_op_estack(ep + 3, cie_cache_finish);
564 esp += 9;
565 /*
566 * The caches are embedded in the middle of other
567 * structures, so we represent the pointer to the cache
568 * as a pointer to the container plus an offset.
569 */
570 make_int(ep + 2, (char *)pcache - (char *)container);
571 make_struct(ep + 1, space, container);
572 return o_push_estack;
573 }
574 /* Note that pc3 may be 0, indicating that there are only 3 caches to load. */
575 int
cie_prepare_caches_4(i_ctx_t * i_ctx_p,const gs_range * domains,const ref * procs,cie_cache_floats * pc0,cie_cache_floats * pc1,cie_cache_floats * pc2,cie_cache_floats * pc3,void * container,gs_ref_memory_t * imem,client_name_t cname)576 cie_prepare_caches_4(i_ctx_t *i_ctx_p, const gs_range * domains,
577 const ref * procs,
578 cie_cache_floats * pc0, cie_cache_floats * pc1,
579 cie_cache_floats * pc2, cie_cache_floats * pc3,
580 void *container,
581 gs_ref_memory_t * imem, client_name_t cname)
582 {
583 cie_cache_floats *pcn[4];
584 int i, n, code = 0;
585
586 pcn[0] = pc0, pcn[1] = pc1, pcn[2] = pc2;
587 if (pc3 == 0)
588 n = 3;
589 else
590 pcn[3] = pc3, n = 4;
591 for (i = 0; i < n && code >= 0; ++i)
592 code = cie_prepare_cache(i_ctx_p, domains + i, procs + i, pcn[i],
593 container, imem, cname);
594 return code;
595 }
596
597 /* Store the result of caching one procedure. */
598 private int
cie_cache_finish_store(i_ctx_t * i_ctx_p,bool replicate)599 cie_cache_finish_store(i_ctx_t *i_ctx_p, bool replicate)
600 {
601 os_ptr op = osp;
602 cie_cache_floats *pcache;
603 int code;
604
605 check_esp(2);
606 /* See above for the container + offset representation of */
607 /* the pointer to the cache. */
608 pcache = (cie_cache_floats *) (r_ptr(esp - 1, char) + esp->value.intval);
609
610 pcache->params.is_identity = false; /* cache_set_linear computes this */
611 if_debug3('c', "[c]cache 0x%lx base=%g, factor=%g:\n",
612 (ulong) pcache, pcache->params.base, pcache->params.factor);
613 if (replicate ||
614 (code = float_params(op, gx_cie_cache_size, &pcache->values[0])) < 0
615 ) {
616 /* We might have underflowed the current stack block. */
617 /* Handle the parameters one-by-one. */
618 uint i;
619
620 for (i = 0; i < gx_cie_cache_size; i++) {
621 code = float_param(ref_stack_index(&o_stack,
622 (replicate ? 0 : gx_cie_cache_size - 1 - i)),
623 &pcache->values[i]);
624 if (code < 0)
625 return code;
626 }
627 }
628 #ifdef DEBUG
629 if (gs_debug_c('c')) {
630 int i;
631
632 for (i = 0; i < gx_cie_cache_size; i += 4)
633 dlprintf5("[c] cache[%3d]=%g, %g, %g, %g\n", i,
634 pcache->values[i], pcache->values[i + 1],
635 pcache->values[i + 2], pcache->values[i + 3]);
636 }
637 #endif
638 ref_stack_pop(&o_stack, (replicate ? 1 : gx_cie_cache_size));
639 esp -= 2; /* pop pointer to cache */
640 return o_pop_estack;
641 }
642 private int
cie_cache_finish(i_ctx_t * i_ctx_p)643 cie_cache_finish(i_ctx_t *i_ctx_p)
644 {
645 return cie_cache_finish_store(i_ctx_p, false);
646 }
647 private int
cie_cache_finish1(i_ctx_t * i_ctx_p)648 cie_cache_finish1(i_ctx_t *i_ctx_p)
649 {
650 return cie_cache_finish_store(i_ctx_p, true);
651 }
652
653 /* Push a finishing procedure on the e-stack. */
654 /* ptr will be the top element of the o-stack. */
655 int
cie_cache_push_finish(i_ctx_t * i_ctx_p,op_proc_t finish_proc,gs_ref_memory_t * imem,void * data)656 cie_cache_push_finish(i_ctx_t *i_ctx_p, op_proc_t finish_proc,
657 gs_ref_memory_t * imem, void *data)
658 {
659 check_estack(2);
660 push_op_estack(finish_proc);
661 ++esp;
662 make_struct(esp, imemory_space(imem), data);
663 return o_push_estack;
664 }
665
666 /* ------ Initialization procedure ------ */
667
668 const op_def zcie_l2_op_defs[] =
669 {
670 op_def_begin_level2(),
671 {"1.setcieaspace", zsetcieaspace},
672 {"1.setcieabcspace", zsetcieabcspace},
673 {"1.setciedefspace", zsetciedefspace},
674 {"1.setciedefgspace", zsetciedefgspace},
675 /* Internal operators */
676 {"1%cie_defg_finish", cie_defg_finish},
677 {"1%cie_def_finish", cie_def_finish},
678 {"1%cie_abc_finish", cie_abc_finish},
679 {"1%cie_a_finish", cie_a_finish},
680 {"0%cie_cache_finish", cie_cache_finish},
681 {"1%cie_cache_finish1", cie_cache_finish1},
682 op_def_end(0)
683 };
684