xref: /plan9/sys/src/cmd/gs/src/zcie.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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